
做毕业设计那会儿我选的是“基于JavaSpringBootSSM的智慧医疗管理系统”。这题目一看就是典型的Java Web综合项目市面上相关源码和论文也不少但真正能跑通、能讲清楚、能扛住答辩追问的其实没几个。我花了不少时间从需求梳理到前后端联调把整套系统走了一遍过程中踩了不少坑也总结了一些经验。这篇博文就围绕这个智慧医疗管理系统项目聊聊核心设计、技术选型、功能实现和调试心得给正在做类似选题的同学一份能直接“抄作业”的参考。这套系统面向的是医疗信息化场景核心解决的是传统门诊流程中挂号排队、病历纸质化、数据分散的问题。功能上覆盖了患者端、医生端和管理员端三类角色包含预约挂号、电子病历、处方管理、药品库存、数据统计等模块。做这套项目用到的主要技术栈是Java、SpringBoot、SSMSpring SpringMVC MyBatis前端用Thymeleaf模板引擎加Bootstrap框架配合MySQL数据库存储业务数据。1. 项目整体设计与需求拆解1.1 为什么选SpringBoot SSM这套组合先说选型。现在做Java Web项目市面上主流选项其实就那几个SSHStruts2 Spring Hibernate已经过时不提了SpringBoot SSM是目前非常成熟的组合方案既能体现Java基础功底又能展示主流框架的整合能力而且SpringBoot自带的自动配置特性可以极大降低SSM整合时的配置复杂度。有个细节要厘清SSM指的是Spring SpringMVC MyBatisSpringBoot只是一个快速开发脚手架。所以“SpringBoot SSM”本质上是在SpringBoot框架下继续保持Spring管理Bean、SpringMVC处理请求、MyBatis操作数据库这套经典分层架构。SpringBoot负责自动配置和启动SSM负责业务逻辑和数据处理。这两个层级不冲突SSM是内核SpringBoot是外壳。这种组合有几个实打实的好处。第一面试和答辩有东西可讲。不管是Spring的IOC/AOP还是SpringMVC的请求流转、MyBatis的动态SQL都是Java面试的高频考点。用这套组合做项目意味着你能把知识体系和实际项目对应上老师问“你们项目里哪里用到了AOP”你可以说日志记录和事务管理都用到了。第二开发效率高出纯SSM不少。我之前尝试过不用SpringBoot直接配SSM光是spring、springmvc、mybatis的XML配置文件就写了一堆还要手动配置数据源、事务管理器、扫描路径稍不注意版本不兼容就得折腾半天。换成SpringBoot后很多东西只需要在application.yml里写几行配置就能搞定。第三社区资料丰富。这个组合做的人太多了遇到问题基本都能搜到解决方案不会卡住太久。这一点对毕业设计周期来说非常重要。1.2 功能模块划分与角色权限模型需求拆解这一步我建议先做别急着写代码。传统的智慧医疗系统覆盖的业务面其实很广但如果全做进去工作量会失控。毕业设计不是商业项目核心是把主干流程走通、把技术亮点展示出来所以我把功能划分为三个角色、六大模块。三个角色分别是患者Patient注册登录、浏览科室和医生、在线预约挂号、查看个人病历和检查报告。医生Doctor查看当天预约列表、书写电子病历、开处方、管理患者档案。管理员Admin管理科室信息、管理医生账号、管理药品库存、查看统计数据、处理公告发布。六大模块对应的是系统登录与用户管理、科室与医生信息展示、预约挂号管理、电子病历与处方管理、药品库存管理、数据统计与可视化。这种划分逻辑的背后是医院业务流程的主线患者挂号 → 医生接诊 → 病历记录 → 处方开药 → 药房取药。每一步对应一个功能模块不多余也不缺失演示起来逻辑流畅答辩时讲业务流程也顺。角色权限模型我用的是SpringMVC拦截器实现的简单RBAC基于角色的访问控制不同角色登录后只能访问自己权限范围内的URL。这一块的技术点也是答辩时老师比较喜欢问的地方后面我会展开讲具体实现。2. 技术选型与核心配置解析2.1 环境版本搭配与工程结构环境这块我的搭配方案是JDK 1.8 Maven 3.6.3 MySQL 5.7 SpringBoot 2.3.4.RELEASE。这个版本组合是我实际验证过稳定运行的强烈建议照着配不要盲目追求新版本否则容易碰到兼容性问题。具体到框架版本SpringBoot 2.3.4对应Spring 5.2.9、SpringMVC 5.2.9、MyBatis Spring Boot Starter 2.1.3。这几个版本搭配相当成熟网上报错案例最少即使出问题也很容易找到解决方案。工程结构我采用的是标准的Maven多级目录包名结构如下com.hospital ├── controller // 控制层接收前端请求、返回视图或数据 ├── service // 业务逻辑层处理具体业务逻辑 │ └── impl // Service接口实现类 ├── mapper // 数据访问层MyBatis的Mapper接口 ├── entity // 实体层数据库表的映射POJO ├── interceptor // 拦截器登录校验、权限控制 ├── config // 配置类WebMvc配置、MyBatis配置、拦截器注册 ├── common // 公共类统一返回结果、常量、工具类 └── HospitalApplication.java // SpringBoot启动类这样的分层结构有讲究。Controller只负责接收和响应Service只负责业务逻辑Mapper只负责数据库操作各层之间通过接口解耦。这样做的好处是项目结构清晰分工明确调试时能快速定位问题在哪一层。2.2 数据层设计与MyBatis配置要点数据库设计是整套系统的基础表结构设计的质量直接决定后期开发效率。我一共设计了7张核心表用户表、患者信息表、医生信息表、科室表、预约挂号表、病历表、药品表外加一个药品库存表。这里给出一个简要的表结构关系说明。数据表核心字段关联关系sys_user用户表user_id, username, password, role_id角色区分1患者2医生3管理员patient_infopatient_id, user_id, name, age, gender, id_card关联sys_user.user_iddoctor_infodoctor_id, user_id, name, dept_id, title关联sys_user和deptdepartmentdept_id, dept_name, intro科室基础信息appointmentappt_id, patient_id, doctor_id, date, time_slot, status预约记录状态区分待就诊/已完成/已取消medical_recordrecord_id, patient_id, doctor_id, diagnosis, prescription病历记录处方内容冗余存储drugdrug_id, drug_name, spec, price, stock药品与库存一体设计这里我想特别强调一下预约挂号表的状态设计。刚开始我只设计了一个简单的时间字段后来发现药品库存、医生排班、患者就诊状态之间没法联动于是增加了status字段0待就诊、1已完成、2已取消和time_slot字段区分上午和下午。状态字段的价值在于患者端能随时查询自己的挂号状态医生端能根据状态快速处理接诊管理员能根据状态统计数据。这种设计思路也可以延伸到其他业务场景中——任何一条业务数据只要有生命周期变化就一定要考虑状态字段。MyBatis映射这块我遇到的最大坑是Java对象属性与数据库下划线字段的映射。MySQL里习惯用user_id这种下划线命名Java里用userId这种驼峰命名如果不在配置里开启驼峰映射查询结果就会出现属性全部为null的情况。解决办法很简单在application.yml里加上这段配置mybatis: configuration: map-underscore-to-camel-case: true mapper-locations: classpath:mapper/*.xml type-aliases-package: com.hospital.entity这段配置的意思是把数据库的下划线字段自动映射为Java的驼峰属性同时指定Mapper XML文件的位置。type-aliases-package配置可以让你在XML文件里直接写实体类名而不用写全路径减少重复代码。2.3 SpringBoot整合SSM的关键配置SpringBoot整合SSM其实核心就是两类配置一是MyBatis的数据源与Mapper扫描二是SpringMVC的拦截器与视图解析。前者在application.yml里完成后者我单独写了一个WebMvcConfig配置类。数据源配置我用的Druid连接池因为Druid提供了监控功能能看到SQL执行情况调试的时候特别有用spring: datasource: name: hospital_db url: jdbc:mysql://localhost:3306/hospital_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource注意一个细节MySQL驱动如果是新版serverTimezone参数必须带上否则会报时区错误。这是个高频坑很多人第一次连数据库都会栽在这里。拦截器注册也要特别注意。SpringBoot的拦截器不能像传统SSM一样直接在XML里配置要写一个配置类继承WebMvcConfigurer然后重写addInterceptors方法Configuration public class WebMvcConfig implements WebMvcConfigurer { Autowired private LoginInterceptor loginInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) .addPathPatterns(/**) .excludePathPatterns(/login, /register, /css/**, /js/**, /images/**, /logout); } }这个排除了登录、注册和静态资源路径其余所有请求都会经过LoginInterceptor做登录校验。校验逻辑很简单从Session中取用户信息如果为空就重定向到登录页。登录拦截器虽然简单但它是整个系统安全性的第一道门槛必须要做。3. 核心功能实现与实操过程3.1 登录认证与权限拦截的实现细节登录功能是每个系统的门面看似简单但涉及的技术点很密集。密码存储我用的MD5加盐处理虽然现在生产环境推荐BCrypt但毕业设计用MD5加盐足够展示思路也方便讲解。登录流程拆解开是这几步前端表单获取用户名和密码通过Ajax提交到后端登录接口。Controller调用Service的login方法Service层根据用户名查询用户表。查询结果判断用户是否存在、密码是否匹配、账号是否被禁用。验证通过后将用户信息存入Session并跳转到对应角色首页。这里有个设计细节登录后跳转的页面需要根据角色区分。我在用户表里设计了role_id字段0是超级管理员1是医生2是患者。登录成功后根据role_id跳转到不同的首页。权限拦截器的实现是这套系统的一个亮点。拦截器里面做角色权限判断时要注意如果只是判断“是否登录”三个角色共享一套代码就够了。但如果要做到“患者不能访问管理员页面”就需要在拦截器里做角色匹配。我的做法是在Controller类上加上PreAuthorize注解配合拦截器判断不过更简单的方案是针对不同角色的URL前缀做限制。比如/admin/**开头的路径只有管理员能访问/doctor/**开头的路径只有医生能访问/patient/**开头的路径只有患者能访问。拦截器里判断当前Session中的用户角色是否匹配URL前缀不匹配就返回403页面。做这个拦截器时我还遇到过一个小坑Session超时后Ajax请求会拿到一个重定向的HTML页面而不是JSON数据导致前端报解析错误。解决办法是在拦截器中判断是否是Ajax请求如果是就直接返回状态码401前端统一处理跳转登录页。3.2 患者档案与预约挂号流程实现患者注册登录后需要完善个人档案信息才能挂号。档案表包含姓名、性别、年龄、身份证号、手机号、既往病史等字段。预约挂号是整个系统业务链路的起点。流程是这样的患者在科室列表页选择科室进入科室详情页查看该科室下的医生列表选择医生后进入排班页面选择日期和时段上午还是下午确认后生成一条预约记录。这个功能的核心难点在并发控制。如果一个号源被两个患者同时预约怎么办我在设计号源表时给每个医生每天的每个时段设置了预约上限比如上午放号30个生成预约记录时先查询已预约数量如果达到上限则提示号源已满。但仅仅是“先查再插”这种模式在并发下是有问题的两个请求同时查询时都发现还剩一个号结果都插入了记录就超了。我当时处理的方案是用SELECT COUNT(*) FOR UPDATE给记录行加锁保证同一时刻只有一个请求在操作同一个号源。虽然性能上有一点牺牲但这种场景并发量本身不大完全够用。在实际的互联网医疗平台里一般用Redis的原子自增或者分布式锁来抗并发原理思路是相通的。这块功能涉及的表关联较多我贴出核心的预约生成逻辑SQL操作-- 检查当前号源剩余量 SELECT COUNT(*) FROM appointment WHERE doctor_id #{doctorId} AND date #{date} AND time_slot #{timeSlot} AND status ! 2; -- 插入预约记录 INSERT INTO appointment (patient_id, doctor_id, date, time_slot, status, create_time) VALUES (#{patientId}, #{doctorId}, #{date}, #{timeSlot}, 0, NOW());第一句查询返回的数字如果小于该时段号源总数就允许第二句插入。整个流程包裹在事务中保证数据一致性。这种检查加写入的流程设计放在电商项目里就是“下单前先锁库存”的简化版。3.3 电子病历与处方管理的关键逻辑医生登录系统后首先看到的是当天预约列表。点击某个患者即可进入接诊页面查看患者基本信息然后填写电子病历。电子病历表单包括主诉、现病史、既往史、检查结果、诊断结论、处理意见等字段。这里我用了一个比较典型的表单提交流程医生填写病历信息点击保存时后端做数据校验包括字段非空校验和格式校验然后写入medical_record表。处方管理是跟电子病历联动的一个子模块。医生在病历下面填写处方信息包括药品名称、剂量、用法用量、天数等。处方数据跟病历存在同一表单下通过一个外键关联。这个设计里有一个容易忽略的点品库存扣减的时机。我一开始是在医生保存处方时就直接扣减库存后来发现这是不合理的——因为医生写处方时药品并没有真正被领走患者可能还没去药房取药。后来改成处方状态分为“已开立”和“已领取”药品库存只有在患者到药房领取处方、状态变为已领取时才扣减。这就是“延迟扣库存”的思路类似的场景在电商系统里也很常见。为了方便演示我在后台数据看板中做了一张处方状态汇总表能直观展示已开立和已领取的处方数量。这个细节在答辩时被老师问过也成了讲业务闭环的切入点。3.4 数据统计与可视化看板实现管理员的首页我设置了三个核心数据面板每日挂号量、患者新增趋势、科室就诊占比。这三个统计指标基本能覆盖管理人员对医院运营情况的核心关注点。数据统计功能实现方式有两种选择一是直接SQL聚合查询二是用ECharts等前端图表库做可视化。我采用的是后端SQL聚合 前端ECharts渲染的组合方案。后端统计接口的核心就是几条SQL聚合语句比如按日期统计挂号量SELECT DATE_FORMAT(create_time, %Y-%m-%d) AS day, COUNT(*) AS total FROM appointment WHERE create_time #{startDate} AND create_time #{endDate} GROUP BY DATE_FORMAT(create_time, %Y-%m-%d) ORDER BY day;这段SQL利用GROUP BY按天分组用COUNT统计每天挂号数量。前端拿到JSON数组后用ECharts画折线图一眼就能看出每天的数据趋势。科室就诊占比用的是类似思路但按dept_id分组查出各科室的接诊量占比。饼图展示效果非常直观也是演示环节最容易出彩的部分。这里提醒一下ECharts引入方式不要用npm这是Java项目不是前端项目。直接用Thymeleaf模板在页面里引入ECharts的CDN地址数据通过Ajax从后端接口拉取然后setOption渲染。如果用npm那套流程反而会把项目搞得复杂难维护。数据可视化这块还有一个重要价值就是让你的项目区别于普通的管理系统——有了图表和数据大屏元素整个系统的“智慧”感就出来了整体档次会高不少。毕业设计展示效果和答辩评分都会因为这个加分。4. 常见问题排查与调试实录4.1 SpringBoot与旧版SSM的版本冲突做整合时遇到最无语的问题就是版本冲突。SpringBoot 2.x内置的Spring 5.x和我引入的一些老SSM依赖冲突启动时直接报错不是循环依赖就是ClassNotFound。印象最深的一次启动时一直报java.lang.NoSuchMethodError查了半天发现是项目里引入了两个版本不同的Spring相关Jar包Maven依赖树里既有SpringBoot统一管理的5.2.9版本又有自己手动引入的旧版5.0.8。当Maven发现同一个包有多个版本时默认会选最近的那个而不是最新的于是旧版本得以保留方法签名对不上就报错了。解决方法是排查pom.xml中是否有重复引入的Spring依赖把冗余的依赖全部删掉让SpringBoot统一管理版本。在pom文件里用dependencyManagement锁定SpringBoot的BOM清单这样依赖版本就会一致。排查这类问题有一个非常管用的工具命令mvn dependency:tree这个命令会把项目所有依赖以树状结构打印出来重复依赖、版本冲突一目了然强烈建议作为定位依赖问题的第一招。4.2 MyBatis映射文件与接口绑定失败MyBatis有个经典问题Mapper接口和XML映射文件明明都写了但一启动就报Invalid bound statement (not found)。这个问题的根本原因是SpringBoot扫描不到XML文件。SpringBoot默认只扫描classpath下的java包不会扫描到XML资源文件而XML文件如果放在src/main/java下Maven构建时不会自动打包到classes目录里。我刚遇到这个问题时看了一眼target目录发现里面根本没有mapper的XML文件。解决方案有两个一是把XML文件放到src/main/resources/mapper目录下二是在pom.xml里配置资源过滤。我用的是第一种方案最简单也最稳妥resources resource directorysrc/main/java/directory /resource resource directorysrc/main/resources/directory /resource /resources如果XML文件确实要放在java目录下就需要用这个配置让Maven把XML一起打包。这个坑太常见了我见过好多人在这个上面卡了一下午排查方向还总往代码逻辑上找其实是资源配置的问题。4.3 前端联调与跨域问题我把后端端口设置成8080前端静态页面直接用Thymeleaf渲染同源情况下不会出现跨域问题。但如果前端做了前后端分离——比如用了Vue或者单独起了一个静态服务——那么跨域问题就躲不掉了。有一次我用Vue调试时浏览器控制台一直报CORS错误接口请求发不出去。解决办法在后端写一个CORS配置类允许指定来源的跨域访问Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*) .allowCredentials(true); } }注意allowedOriginPatterns不要写成allowedOrigins(*)因为allowCredentials(true)时安全策略不允许通配域名。SpringBoot 2.4版本之后这个规则尤其严格用allowedOriginPatterns可以直接绕过这个坑。前端联调还有一个建议统一使用Ajax封装函数统一处理请求超时和错误提示。不要每个页面单独写Ajax调用那样代码冗余不说改一个公共逻辑要改几十个地方。抽一个common.js文件封装get和post方法所有页面统一调用。这是工程化的小习惯答辩时老师看了会认为你有一定的项目规范意识。4.4 调试文档撰写经验项目做完后还需要调试文档。虽然系统的功能是能跑了但作为一个完整交付的源码项目调试文档的价值在于让使用的人能快速在你写好的代码基础上二次修改也让答辩评委能看懂系统的技术设计。调试文档我是按照标准结构来组织的项目环境要求JDK版本、MySQL版本、Maven版本、IDE版本。部署步骤导入项目→修改数据库配置→创建数据库并导入SQL→启动项目→访问地址。功能模块说明各角色的操作流程和核心页面截图。常见问题FAQ上述版本冲突、Mapper扫描不到、数据库连接失败等问题的解决方案。调试文档实际上是你对整个项目理解深度的试金石。如果你能把自己的调试文档写清楚说明你是真的把这个项目吃透了答辩时遇到的“这东西怎么部署”之类的问题也基本不会难住你。5. 论文写作与答辩准备的实战心得5.1 毕业设计论文结构搭建技巧论文虽然不在代码项目交付范围内但作为毕业设计的另一半考察点分量和源码不相上下。智慧医疗系统这类选题的论文我建议按这个结构写第一章是绪论讲智慧医疗的背景和意义国外研究现状国内研究现状最后引出课题目标和内容。这一章的重点是“为什么要做这个系统”背景要写充分但不要堆砌无意义的空话。第二章是相关技术介绍每项技术用一个小节说明背景、核心概念和选择理由。这里不要直接抄技术文档要结合项目实际情况去写比如“为什么选MyBatis而不是Hibernate”、“为什么用SpringBoot整合SSM而非纯SSM”展示的是你的选型思考能力。第三章是系统分析包括可行性分析、需求分析、功能模块分析和用例分析。这一章的内容来自你之前做的需求拆解适当扩充即可。第四章是系统设计包括总体架构设计、功能模块设计、数据库设计和接口设计。数据库设计最好配上ER图功能模块配上功能结构图。第五、六章是系统实现每个模块一小节配合核心代码片段和运行效果截图。界面截图要清晰代码放关键的逻辑即可不要整段粘贴。最后是系统测试和总结展望。测试部分重点写测试用例和测试结果用表格形式展示用例名称、操作步骤、预期结果、实际结果。总结部分写自己做了什么、学到了什么展望写后续可以增加什么功能。5.2 答辩讲解与技术问答准备答辩时老师最常问的问题是围绕技术选型和项目细节这里整理一下我当时被问到的几类高频问题。第一类“为什么选SpringBoot而不是直接用SpringMVC”回答思路是SpringBoot简化配置、内置Tomcat方便部署、自动配置减少开发工作量而SpringMVC核心功能本质上在SpringBoot中同样具备。第二类“数据库表的关联关系怎么设计的”要能快速在纸上画出表关系图讲清楚用户、患者、医生、挂号、病历、药品之间的外键关系。第三类“这个系统如果上线哪些地方还存在不足”诚实列出优化点即可比如没有做密码加盐、没有做Redis缓存、没有做数据库主从分离。然后补充说明如果是生产级系统会采用哪些改进方案。展示的是你的延伸思考能力。答辩很容易紧张但如果你真的动手写过代码、跑通过系统、整理过调试文档心里是有底的不建议背稿子把自己实际做的事情讲出来自然就是最好的答辩状态。6. 项目功能演示要点与优化扩展方向6.1 项目演示的核心操作流程演示环节是决定第一印象的关键。我的建议是提前设计一条演示路径不用把所有功能都点一遍而是走通一个有业务闭环的场景也就是“患者注册登录→预约挂号→管理员分配医生→医生接诊→填写病历处方→患者查看报告”这条链路。演示的时候有一些细节会让观感完全不同。比如提前准备好测试数据把医生排班信息填好、药品库存备足避免演示中途出现空列表这种尴尬情况。浏览器窗口提前调整到合适尺寸不要让页面在演示时出现横向滚动条。还有页面之间的跳转逻辑要熟练中途不要反复切来切去找功能入口。如果时间充裕还可以演示一下数据统计页面的图表联动效果。这个功能做得好会给评委留下“系统完整度高”的印象因为很多项目只做了增删改查统计可视化这层往往是加分项。6.2 系统扩展与后续开发方向做完这套系统之后如果你的时间还够可以考虑加几个有亮点的扩展功能。这些扩展写在论文的展望部分也会加分。第一个可以加的是JWT无状态登录。目前Session登录方案在集群部署场景下有天然的缺陷换成JWT后每次请求携带Token后端无需保存会话状态这也更接近现在企业项目的实际做法。第二个可以考虑的是引入Redis做缓存。比如科室列表、医生排班、药品信息这类热点数据完全可以缓存到Redis里减轻数据库压力。这块改动不算太大但技术含金量会有明显提升。第三个方向是加一个简单的数据报表导出功能用POI把统计结果导出成Excel文件。功能不难但实用性强而且能多展示一类技术栈。这些延展内容做不做取决于你的学力余量和答辩时间不建议为了扩功能而牺牲质量核心链路跑通之后增值功能量力而行就好。7. 从零到一搭起智慧医疗系统的复盘回头看整个项目的开发过程我认为最值得记住的并不是某个技术点而是完整的项目思维。技术能力之外做得最多的是取舍判断。一个真实的智慧医疗系统涉及的模块非常多包括挂号、收费、药房、住院、检验、影像等涉及的系统更是复杂。毕业设计阶段不可能全部做能做什么、不做什么、做到什么深度这些判断比编码本身更重要。我把主干流程定为核心辅助功能按需裁剪既保证了系统闭环又没有让工作量失控。遇到问题时的排查思路同样值得沉淀。一个个报错信息背后其实对应的是框架运行机制的理解深度。SpringBoot启动报错是依赖问题还是配置问题MyBatis查询结果为空是映射问题还是SQL问题前端数据不显示是接口问题还是渲染问题——这种梳理问题、定位问题、解决问题的能力才是做项目真正能给到你的长期回报。最后说个实在的这个项目做完我对Java后端开发的整体认识比上课半年收获都大。SpringBoot的自动配置、MyBatis的映射机制、SpringMVC的请求生命周期原来都是零散的知识点做完一个完整项目之后它们在我脑子里串成了一整条链路。如果你现在正卡在某个环节——不管是环境跑不起来、Mapper扫不到、还是某个功能逻辑绕不清楚——我的建议是别慌先把报错信息完整读一遍再去定位代码位置最后才搜解决方案。这套排查路径走熟了你会发现大部分问题其实原理都很简单只是第一次遇到时会比较懵。这套智慧医疗管理系统的经验分享就写到这里。我踩过的那些坑你大概率也会碰到希望这篇文章能帮你少走几步弯路。如果你做完之后也想加点自己的功能、踩到了新的有意思的坑欢迎回来一起交流。