社区医院管理系统这种项目,几乎是Java后端开发者绕不开的一道经典考题,尤其在毕设和企业内部小系统里,"SpringBoot+Vue+MyBatis+MySQL"这套组合出现频率高得惊人。说它是全栈入门到进阶的"标准动作"一点不为过。我从单体JSP时代做到前后端分离,中间踩坑无数,最后稳定在这套技术栈上,不是因为它新潮,而是因为它足够务实:后端够轻、前端够灵活、数据库方案最普及,社区医院这类中小型机构的预算和运维水平也完全hold得住。
这篇文章不写营销式的功能介绍,直接把这套系统的需求拆解、技术选型逻辑、数据库设计、前后端关键实现、部署避坑一次讲透。适合正在做毕业设计的学生,也适合刚接手的初级开发者照着落地。你照着做,至少能少走半个月弯路。
1. 项目定位:社区医院管理系统到底在管哪些事
1.1 社区医院日常运转里的三个核心痛点
社区医院跟三甲医院完全是两种物种。三甲医院讲究的是分院区、分科室、多系统集成,而社区医院最真实的场景是:地方不大、人手紧张、流程却一样也不能少。患者进门先挂号,医生看诊后开处方,收费处结算,药房发药,整个过程全靠纸质单据和Excel来回倒,高峰期排队长不说,账目对不上是常有的事。
我自己调研过的几家社区医院,最常见的痛点集中在三个方向。
第一个是挂号与排队管理混乱。患者姓名、就诊时间、医生排班全靠手写登记,医生临时调班患者根本不知道,爽约率居高不下,号源浪费严重。
第二个是药品与库存脱节。处方开完了,药房才发现库存不够或者效期不对,处方只能作废重开,医生和患者耗在来回沟通上的时间非常多。
第三个是收费与病历对账困难。药品价格变动、医保比例调整,收费员手算容易错,月底盘点财务报表全靠人工核对,错一笔就要逐单查。
所以社区医院管理系统的核心,不是把医院的所有业务塞进去,而是把"挂号—看诊—开方—收费—取药—库存"这条主流程跑通,同时把患者档案沉淀下来。项目在设计之初就应该围绕这条主线来切模块,而不是贪大求全。
1.2 功能模块拆解与角色边界
这个系统的角色我最终收敛为四类,每类角色看到的界面和能操作的功能是严格区分的:
| 角色 | 核心职责 | 涉及模块 |
|---|---|---|
| 系统管理员 | 账号维护、科室与医生排班、基础数据字典 | 用户管理、科室管理、排班管理 |
| 医生 | 患者接诊、病历填写、处方开具 | 挂号队列、诊断填写、处方管理 |
| 收费员 | 费用结算、退费处理、日结报表 | 收费管理、退费管理 |
| 药房管理员 | 药品出入库、库存预警、处方发药 | 药品管理、库存管理、发药核销 |
功能模块拆解下来,大致是这几个核心块:登录认证、患者档案管理、科室与医生排班、挂号管理、诊断与处方管理、药品与库存管理、收费结算、系统统计报表。这些模块中有两个很容易被新手忽略,但恰恰是企业级评价的重点。
第一个是挂号与号源状态流转。挂号的常见状态是预约、已就诊、已取消,但这个状态需要由医生接诊动作来触发变更,不能靠挂号员手工改,否则数据一致性很差。
第二个是库存与处方核销的联动。药房发药不是简单减库存,而是要标记某张处方已经"发药完成",防止同一张处方二次领药。这两个业务规则在设计数据库时就要考虑进去,后面改起来非常麻烦。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型拆解:SpringBoot+Vue+MyBatis+MySQL为什么能打
2.1 后端为什么是SpringBoot而不是SSH
很多老教程还在教SSH,也就是Struts2+Spring+Hibernate那套。说实话,那套架构在2025年的今天已经不太适合新项目了,配置繁琐、依赖臃肿、社区活跃度低,招人也难招。SpringBoot的核心价值是"约定大于配置",内嵌Tomcat,一个jar包就能跑起来,这对社区医院这种没有专业运维人员、服务器环境可能很简陋的场景来说,是降维打击。
SpringBoot另一层价值是生态成熟。Spring Security做登录鉴权、Spring Data做数据访问、Spring Validation做参数校验,都有现成的starter可以直接引入,不需要造轮子。我在实际项目里还发现一个容易被忽视的好处:SpringBoot的自动配置让环境迁移成本极低。开发环境用H2内存库快速调试,生产环境切换MySQL,只需要改配置,一行业务代码不动。
不过SpringBoot也有需要注意的地方。版本选择要克制,不建议一上来就追最新版本。我用得最稳的组合是Spring Boot 2.7.x + JDK8,这套组合经过了大量生产环境验证,资料多、踩坑经验多,出了任何报错都能搜到解决方案。JDK8很多新人不愿意用,但实际上社区医院系统这种并发量级,JDK8完全够用,没必要为了"新"而上JDK17,反而增加兼容性风险。
2.2 MyBatis凭什么比JPA更适合这类项目
选型MyBatis而不是Spring Data JPA,是我在第二版重构时做的决定。JPA很强,面对纯CRUD能省很多事,但社区医院系统有大量自定义统计查询,比如按月份统计科室收入、按药品统计消耗量,这些SQL往往需要JOIN三张以上的表,JPA的QueryDSL写起来非常绕,最终还是要落到原生SQL。
MyBatis的核心优势是SQL可控。你写的每一句SQL自己都清楚,SQL执行计划也可以直接拿出来分析,这在排查性能问题时特别有用。另一方面MyBatis的mapper接口加XML的方式,钱货分离,SQL写在XML里,Java代码只保留业务逻辑,后期维护比拼接SQL字符串清晰得多。
这里有一个很多人没注意到的细节:MyBatis的二级缓存默认是关闭的,我建议保持关闭。社区医院系统是典型的读多写少,但药品库存和收费记录对实时性要求很高,缓存一旦脏读,账目就错了。宁可把单表查询的SQL优化到位,也不要轻易开缓存。
2.3 Vue作为前端框架的取舍与版本选择
前后端分离现在已经是大势所趋,尤其在这个项目里,医生看诊界面可能是一个窗口,收费处是另一个窗口,药房是第三个窗口,三处同时操作同一套数据,前端自然要拆成独立工程。
Vue相比React的上手曲线更平缓,模板语法对后端出身的开发者非常友好。在版本选择上,如果是二开或者参考老代码,很可能是Vue2+Element UI;如果是全新项目,我更推荐Vue3+Vite+Element Plus。Vue3的Composition API在复杂业务逻辑复用上优势明显,比如挂号页面和收费页面都要用到的"患者信息面板",抽成一个组合式函数,两处引用,比Vue2的mixin更清晰。
但Vue3也有一些实际成本:生态里面部分第三方组件还停留在Vue2版本,Element Plus的个别组件行为与Element UI并不完全一致。所以我的建议是,如果你对Vue还不熟,直接用Vue2学起来更顺;如果你已经有Vue2基础,直接上Vue3提升一下自己,两者代码结构差异不算大。
3. 数据库设计:一张好表胜过十次重构
3.1 核心表结构与关联关系梳理
社区医院管理系统数据库设计的第一原则是"跟着业务流程走"。我从第一版开始就坚持画ER图,把"挂号—诊断—处方—发药—收费"这条主链在表结构上完整地体现出来。核心表数量大概在12到15张之间,不用多,多了是负担,少了业务串不起来。
| 数据表 | 存放内容 | 关键字段说明 |
|---|---|---|
| sys_user | 系统用户账号 | 用户名、密码(MD5加盐或BCrypt)、角色标识、所属科室 |
| patient | 患者档案 | 姓名、性别、身份证号、联系方式、既往病史 |
| registration | 挂号记录 | 患者ID、医生ID、号源日期、时段、挂号状态(预约/已就诊/已取消) |
| medical_record | 诊断病历 | 挂号ID、主诉、现病史、诊断结论、处理意见 |
| prescription | 处方主表 | 病历ID、医生ID、总金额、处方状态(待收费/已收费/已发药) |
| prescription_item | 处方明细表 | 处方ID、药品ID、数量、单价、小计 |
| drug | 药品信息 | 药品编码、通用名、规格、生产厂家、零售价 |
| drug_stock | 药品库存 | 药品ID、批号、库存数量、有效期、预警阈值 |
| charge_record | 收费记录 | 处方ID、收费金额、收费方式、收费员、收费时间 |
3.2 字段类型与状态设计的关键细节
数据库设计里最容易被新手忽略的是金额和时间字段的处理。金额一律用DECIMAL(10,2),绝不能用Float或Double。我见过不止一个项目因为金额用float,累计几万条记录后出现一分钱差额,对账对到怀疑人生。时间字段用DATETIME而不是TIMESTAMP,DATETIME没有2038年问题,社区医院这种系统是要用很多年的。
状态字段需要特别注意。以挂号记录为例,REGISTRATION_STATUS从0到2分别是预约、已就诊、已取消。三个状态之间不允许随意跳转,比如"已取消"的挂号不能直接变成"已就诊",必须重新挂号。这个规则在数据库层面可以用状态机约束,但更实用的做法是在Service层做状态校验,把非法流转直接拦截掉。
还有一个特别容易踩坑的点:患者档案的身份证号统一使用VARCHAR(18)存储,不要用数字类型。因为身份证号可能包含字母X,而且即使全是数字,BigInteger存储也会在显示时丢失前导零,到时候哭都来不及。
3.3 索引设计与慢查询预防
社区医院系统数据量不大,单表顶多几十万行,但依然要建索引,目的是让常用查询稳定在毫秒级。我先说结论:主键以外的索引,我只在各表的外键字段和状态字段上建。
挂号表要以PATIENT_ID和DOCTOR_ID建联合索引,因为高频查询是"某个患者的挂号记录"和"某医生某天的号源"。收费记录表要以CHARGE_TIME建普通索引,月度报表统计按时间区间查询时能走索引。处方明细表的外键PRESCRIPTION_ID必须建索引,否则一张处方对应十几条明细,查询明细会变成全表扫描。
索引不是越多越好。每张表加索引都会拖慢写入速度,而且占用更多磁盘空间。社区医院系统的写入频率并不低,收费和发药操作是实时的,所以我的原则是:只为高频查询建索引,不为凑数建索引。
4. 后端核心实现:SpringBoot整合MyBatis的细节都在这
4.1 工程分层与基础配置
后端工程我采用标准的controller-service-mapper三层架构,实体类放在entity包,DTO与VO分开,避免前端字段与数据表字段强耦合。社区医院系统的前端展示需求经常变,比如挂号列表要加一个"医生姓名"字段,如果没有DTO和VO隔离,这种改动就会直接波及实体类和Mapper,非常痛苦。
SpringBoot整合MyBatis的配置其实非常固定,我直接在application.yml里写清楚,照抄就能跑:
yaml复制spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/community_hospital?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 123456
hikari:
maximum-pool-size: 10
minimum-idle: 5
connection-timeout: 30000
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.hospital.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
这段配置里有三个细节必须说明白。第一个是url里必须加serverTimezone=Asia/Shanghai,否则MySQL驱动会报时区错误。第二个是useSSL=false,社区医院内网部署没必须走SSL加密,加了反而容易因为证书问题断连。第三个是map-underscore-to-camel-case设为true,这样数据库下划线字段能自动映射为Java驼峰属性,少写大量resultMap,但需要你建表时命名规范,别混用大小写。
还有一个血泪教训:不要在配置里写密码明文,尤其是提交到Git仓库的项目。社区医院系统虽然内网使用,但代码可能多人开过,密码泄露风险很大。正规做法是使用jasypt加密配置,或者把密码放在环境变量里。
4.2 统一返回结果与全局异常处理
前后端分离项目里,最怕的就是各接口返回格式五花八门。有的接口直接返回JSON数组,有的返回包装对象,前端封装axios时就要不断判断类型,非常痛苦。我在项目开始第一天就定义了统一的Result返回结构,之后所有接口都只返回这一个结构。
java复制public class Result<T> {
private Integer code; // 200成功,500失败,401未登录
private String message;
private T data;
public static <T> Result<T> success(T data) {
Result<T> result = new Result<>();
result.code = 200;
result.message = "操作成功";
result.data = data;
return result;
}
public static <T> Result<T> error(String message) {
Result<T> result = new Result<>();
result.code = 500;
result.message = message;
return result;
}
}
配合全局异常处理器,业务代码里就不需要自己catch异常再手动封装。我的做法是自定义一个BizException,业务校验不通过直接throw new BizException("该药品库存不足"),由@RestControllerAdvice统一捕获并响应给前端。这样做的好处是业务代码干净,不会出现满屏的try-catch,也方便前端根据统一的code判断业务失败。
4.3 登录鉴权与用户身份获取
社区医院系统的登录鉴权,我用的是拦截器加ThreadLocal的方案,没有引入Spring Security全家桶。原因很简单:系统角色只有四类,接口权限控制用自定义拦截器就足够,Spring Security学习成本高,配置复杂,社区医院项目用不上那么重的安全框架。
登录成功后,后端生成一个UUID作为token,存入Redis并设置过期时间,前端每次请求在Header里带上token。拦截器负责校验token,通过后把用户ID存入ThreadLocal,Service层随时通过UserContext.getUserId()拿到当前操作人,收费记录和操作日志里就能自动记录操作人ID。
java复制public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if (StringUtils.isBlank(token)) {
response.setStatus(401);
return false;
}
// 从Redis或数据库校验token,并提取用户信息存入ThreadLocal
UserContext.set(UserContext.parse(token));
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
UserContext.clear(); // 防止线程池复用导致串号
}
}
UserContext最后一定要在afterCompletion里clear掉,否则Tomcat线程池复用线程时,下一个请求可能读到上一个用户的信息,这是非常严重的逻辑漏洞,排查起来还特别隐蔽。
4.4 核心业务事务控制
事务管理是社区医院系统最关键的环节,尤其是收费和发药这两个操作。比如收费成功之后要同时更新处方状态、生成收费记录、修改药品库存,这三步任何一个失败,都不能让部分数据落库。
我的做法是在Service层的方法上直接标注@Transactional。这里有一个重要的细节:@Transactional只对RuntimeException及其子类生效,如果你在代码里catch了异常但没重新抛出,事务是不会回滚的,数据就悄悄写进去了。所以我的规则是业务方法里不自己catch异常,全部交给全局异常处理器。
挂号模块还有一个典型事务场景:患者爽约被取消挂号后,号源要释放给下一位患者。这一类操作要放在同一事务里,只要号源更新失败,取消动作也要回滚,否则会出现"患者已取消但号源还占着"的脏数据。
5. 前端Vue实现:从登录页到核心业务页面的落地过程
5.1 工程搭建与Axios请求封装
前端工程我使用Vue CLI创建,Vue2配Element UI,Vue3配Element Plus。目录结构按模块拆分views、components、api、router、store,这一层不做区分的话,几十个组件混在一起,后期维护非常痛苦。
Axios封装是前端最重要的基建。社区医院系统有四个角色入口,请求需要携带token,也需要区分不同接口的权限。我在api目录下按模块拆分接口文件,比如registration.js、prescription.js、drug.js,每个文件导出一组调用方法,页面组件只管调用,不直接操作axios实例。
javascript复制import axios from 'axios'
import { Message } from 'element-ui'
import router from '@/router'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000
})
// 请求拦截器:自动带上token
service.interceptors.request.use(config => {
const token = sessionStorage.getItem('token')
if (token) {
config.headers['Authorization'] = token
}
return config
}, error => Promise.reject(error))
// 响应拦截器:统一处理错误码
service.interceptors.response.use(response => {
const res = response.data
if (res.code === 401) {
sessionStorage.removeItem('token')
router.push('/login')
return Promise.reject(new Error('未登录'))
}
if (res.code !== 200) {
Message.error(res.message)
return Promise.reject(new Error(res.message))
}
return res
}, error => Promise.reject(error))
export default service
baseURL这里不用写死,社区医院系统开发环境与生产环境接口地址大概率不同,用环境变量文件区分是最稳妥的。.env.development里写好VUE_APP_BASE_API,.env.production里写成实际的公网地址。
5.2 路由守卫与动态侧边栏
社区医院系统的侧边栏菜单不同角色看到的不同,管理员看到系统管理,医生看不到收费菜单。我的做法是在路由配置里给每个路由表加meta字段,标记allowedRoles,然后在路由守卫里动态判断。
javascript复制router.beforeEach((to, from, next) => {
const token = sessionStorage.getItem('token')
if (!token && to.path !== '/login') {
next('/login')
return
}
const user = JSON.parse(sessionStorage.getItem('user'))
if (to.meta.allowedRoles && !to.meta.allowedRoles.includes(user.role)) {
next('/403')
return
}
next()
})
这个方法对菜单渲染和权限拦截都生效,菜单根据user.role过滤,路由根据to.meta.allowedRoles判断是否有权限进入。相比动态添加路由的做法,这种方案简单可靠,适合角色数量固定的系统,不用把权限数据在登录后再拿一次。
5.3 核心业务页面的三个设计细节
挂号页面的核心是不让用户选到已经满号的时段。我从前端做了一道双重校验,医生排班数据从接口获取后,前端就根据"已挂号人数大于等于号源总数"来禁用对应时段,同时后端在保存挂号时再做一次防并发校验,防止两个患者同时抢到最后一个号。前端拦截解决体验,后端拦截解决正确性,两者缺一不可。
处方录入页面是医生使用频率最高、也最容易出问题的场景。我的经验是把处方主表和明细表做成一个表单,明细部分用动态表格实现,每一行选择药品后自动带出价格和库存,点击"加入处方"再校验所选药品库存是否足够。库存不足的药品行直接标红,禁止提交。这个逻辑看似简单,但前端校验和后端校验必须一致,否则就会出现"前端提示库存不足、后端却能直接提交"的逻辑漏洞。
收费页面要展示的是"待收费处方列表",收费员点开处方详情核对金额后点击结算。我特别做了防连点处理,按钮点击后立即置灰,防止收费员手快连续点击,导致同一张处方被收费两次。后端也在事务里做了幂等校验,同一张处方在已收费状态下不会再次生成收费记录。
6. 构建部署与高频报错排查
6.1 生产环境部署方案对比
社区医院系统部署场景两种:一种是医院内网单机部署,一种是云服务器部署。单机部署最简单的方式是直接把Vue打出来的dist目录复制到SpringBoot的static目录下,再打成一个jar包,一条命令java -jar hospital.jar启动,Tomcat和前端静态资源都由SpringBoot统一处理。这个方案胜在简单,适合医院服务器上没有Nginx、也没人懂反向代理的场景。
如果服务器有Nginx,我则更推荐用Nginx托管前端静态资源,利用反向代理把/api开头的请求转发到后端端口。这样前后端物理分离,各自独立升级互不干扰,也是团队协作更舒服的方式。Nginx的关键配置就一小段:
nginx复制server {
listen 80;
server_name your-domain.com;
# 前端静态资源
location / {
root /opt/hospital/dist;
index index.html;
try_files $uri $uri/ /index.html; # 解决Vue路由history模式刷新404
}
# 反向代理后端
location /api/ {
proxy_pass http://127.0.0.1:8080/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
try_files这行是Vue路由history模式的标配,不加的话,用户刷新某个子页面就会404。如果你用hash模式则可以省掉,但URL会带#号,个人觉得不好看。
6.2 SpringBoot打包与前端构建细节
Maven构建的时候,我第一次打生产包没加跳过测试参数,结果单元测试因为连不上测试库直接失败,整个打包流程中断。后面固定使用mvn clean package -DskipTests,一步到位。
前端构建也有一些细节。npm run build之前需要确认.env.production里的API地址是线上地址,不是localhost。还有个容易忽略的问题:前端构建出的dist目录如果直接复制到SpringBoot里,必须重新打包后端,而且后端静态资源缓存清理比较麻烦,所以我倾向于用Nginx方案部署,改前端代码后就只动静态文件,不用重打后端jar。
6.3 高频报错与解决方案速查表
这是我整理的第二版项目里真实遇到过的报错,每一项都对应着一个真实的踩坑记录,直接列出问题现象、原因和解决办法:
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| Access denied for user 'root'@'localhost' | 数据库账号密码或权限不对 | 检查MySQL用户密码,执行GRANT ALL ON 库名.* TO 'root'@'localhost' |
| Unknown database 'community_hospital' | 数据库没建 | 执行CREATE DATABASE community_hospital DEFAULT CHARACTER SET utf8mb4 |
| The server time zone value 'Öйú' is unrecognized | MySQL时区配置错误 | 启动参数加serverTimezone=Asia/Shanghai,或者mysql命令行SET GLOBAL time_zone='+8:00' |
| Invalid bound statement (not found) | Mapper接口与XML的namespace或方法id不匹配 | 核对namespace为接口全限定名,方法id与接口方法名一致 |
| java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed | MySQL8连接串缺少allowPublicKeyRetrieval=true | url参数加上allowPublicKeyRetrieval=true |
| Failed to configure a DataSource | 找不到数据源配置 | 检查application.yml里的spring.datasource配置是否被注释或写错 |
| Request processing failed; nested exception is java.lang.StackOverflowError | 实体类双向引用且重写了toString或JSON序列化无限递归 | 在实体类对多或对一关联字段加@JsonIgnore注解 |
| 前端接口跨域报错 | 前端地址与后端接口地址不在同域 | 后端配置CorsFilter,或前端用Nginx反向代理 |
| Vue刷新404 | history模式下服务端未配置try_files | Nginx配置location /时加上try_files $uri $uri/ /index.html |
| DATE类型传到前端变成字符串少了时分秒 | 时间字段用LocalDateTime但JSON序列化规则不对 | 统一配置jackson的date-format和time-zone属性 |
6.4 数据库初始化与版本管理
社区医院系统多数从零起步,建库脚本不能只在本地有,应该提交到代码仓库里统一管理。我在项目根目录下维护一个sql目录,里面按版本存放建表脚本,比如v1.0_init.sql、v1.1_add_drug_stock.sql。每次变更表结构,都必须新增脚本,而不是修改旧脚本,这样团队协作时数据库结构不会乱。
还有一个实用习惯:正式数据导入前,先在本地跑一遍所有表的增删改查。社区医院系统的药品表初始化可能有上千条记录,如果直接用Excel导入而没做验证,很容易出现药品编码重复或价格字段为空的脏数据,后面处方和库存关联全乱掉。
7. 实操经验总结与建议
第二版项目重构完成后,我最大的体会是:社区医院系统这类项目,技术难度本身不高,难的是业务流程能否被数据模型准确表达。很多毕设项目停留在"能跑就行",但企业级考察的点恰恰是:你是否理解了挂号状态流转、库存与处方联动、事务与并发控制这些真实场景的需求。
如果时间允许,我非常建议在这个系统基础上做三件扩展。第一件是引入日志审计功能,记录每次收费、发药、库存调整的操作人与操作时间,这在医疗行业是不可或缺的合规要求。第二件是加一个简单的药品效期预警,在库存列表里高亮提示三个月内到期的药品,这个功能不算难,但对药房实际使用价值极高。第三件是做一个门诊工作量统计报表,按医生、按月统计接诊人次数和处方金额,很多社区医院领导层每周都要看这份报表。
最后说一个实用小技巧:在开发过程中,把MyBatis的SQL日志打开(配置里log-impl直接用StdOutImpl),每一条SQL语句和查询参数都会打印在控制台。排查"数据对不对"的问题时,第一件事就是看SQL日志,确认实际执行的SQL与业务预期一致,90%的数据异常问题都能在这一步定位到原因。别一开始就怀疑数据库数据有问题,SQL查出来是什么样,很大程度上决定了页面上显示成什么样,日志会让你少做很多无用功。
文章写到这里,核心思路和实操要点基本都覆盖了。这些内容是我从多个实际项目中趟出来的,照着做不敢说一步到位,但至少可以让你少踩几个隐蔽的坑。项目源码结构如果你们拿到手,建议按我前面说的顺序先跑通数据库脚本,再启动后端,最后启动前端,这个顺序能最大化减少初次运行报错的概率。
