1. 项目概述与核心价值
这套基于Spring Boot+Vue+MySQL的疗养院管理系统,是我在2022年为某连锁养老机构交付的商业项目精简版。相比市面上通用的医疗系统,它专门针对疗养院的特殊需求做了深度定制,包含三大核心模块:
- 入住管理:从预约登记到合同签订的全流程电子化,特别设计了家属远程签字功能
- 健康监测:对接常见医疗设备的数据采集,自动生成周/月健康趋势报告
- 服务调度:护工排班与服务请求的智能匹配算法,响应速度提升40%
技术栈选择上,后端采用Spring Boot 2.7 + MyBatis Plus,前端使用Vue 3 + Element Plus,数据库为MySQL 8.0。这套组合在保证性能的同时,极大降低了二次开发门槛——这也是甲方最终选择我们方案的关键因素。
提示:源码已去除敏感业务逻辑,但保留了完整的权限控制体系(RBAC模型+JWT),可直接作为企业级开发脚手架使用。
2. 环境搭建与项目启动
2.1 基础环境准备
需要预先安装:
- JDK 17(兼容11但推荐17)
- Node.js 16.x
- MySQL 8.0(必须开启INNODB引擎)
- Maven 3.8+
配置要点:
# 数据库初始化(注意字符集设置) CREATE DATABASE nursing_home DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; # 前端依赖安装建议使用pnpm npm install -g pnpm2.2 后端启动关键步骤
- 修改
application.yml中的数据库连接:
spring: datasource: url: jdbc:mysql://localhost:3306/nursing_home?useSSL=false&serverTimezone=Asia/Shanghai username: root password: yourpassword- 特殊配置项说明:
spring.cache.type=redis建议生产环境开启mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl调试时启用SQL日志
- 启动类
NursingHomeApplication的特别处理:
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class // 手动配置多数据源时需要 }) public class NursingHomeApplication { public static void main(String[] args) { // 解决Hutool的XSS过滤与Swagger冲突 System.setProperty("hutool.http.filter.xss.ignoreUrl", "/swagger-ui/.*"); SpringApplication.run(NursingHomeApplication.class, args); } }2.3 前端启动注意事项
项目使用了Vite 4.x构建,需注意:
- 环境变量配置在
.env.development:
VITE_API_BASE_URL=http://localhost:8080 VITE_USE_MOCK=false # 演示数据开关- 常见启动问题解决:
# 依赖安装报错时尝试 pnpm install --shamefully-hoist # 端口冲突时修改 vite.config.js -> server: { port: 3000 }3. 核心模块技术解析
3.1 智能排班算法实现
后端ScheduleService中采用的混合调度算法:
public List<Schedule> autoArrange(ShiftRequest request) { // 基于遗传算法的初始排班 List<Schedule> base = geneticAlgorithm(request); // 人工规则二次优化 return ruleEngine.optimize(base, request.getConstraints()); }关键参数说明:
| 参数名 | 作用 | 推荐值 |
|---|---|---|
| populationSize | 遗传种群规模 | 50-100 |
| mutationRate | 变异概率 | 0.01 |
| maxGeneration | 最大迭代次数 | 1000 |
3.2 健康数据可视化
前端采用ECharts实现动态图表,核心逻辑在HealthChart.vue:
const loadData = async () => { const res = await getHealthData({ residentId: props.id, range: timeRange.value // 周/月/季 }); chartInstance.setOption({ series: [{ type: 'line', data: res.data.map(item => ({ value: [item.date, item.bloodPressure], name: item.remark })) }] }); };性能优化点:
- 使用Web Worker处理大数据量
- 开启dataset的dimension压缩
- 防抖处理窗口resize事件
4. 企业级功能扩展建议
4.1 多院区支持改造
- 数据库层面:
ALTER TABLE resident ADD COLUMN branch_id INT NOT NULL DEFAULT 1; CREATE INDEX idx_branch ON resident(branch_id);- 后端实现动态数据源:
@Configuration public class DynamicDataSourceConfig { @Bean public AbstractRoutingDataSource routingDataSource( @Qualifier("masterDataSource") DataSource master, @Qualifier("branchDataSource") DataSource branch) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("master", master); targetDataSources.put("branch", branch); DynamicDataSource ds = new DynamicDataSource(); ds.setTargetDataSources(targetDataSources); ds.setDefaultTargetDataSource(master); return ds; } }4.2 安全加固方案
- 防止XSS攻击的全局过滤器:
@WebFilter("/*") public class XssFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; // 排除Swagger等特殊路径 if (!request.getRequestURI().contains("/api-docs")) { chain.doFilter(new XssHttpServletRequestWrapper(request), res); } else { chain.doFilter(req, res); } } }- 接口幂等性控制示例:
@Idempotent @PostMapping("/checkin") public Result addResident(@RequestBody Resident resident) { // 业务逻辑 }5. 生产环境部署指南
5.1 后端Dockerfile优化版
FROM eclipse-temurin:17-jdk-jammy # 时区设置 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime # JVM参数优化 ENV JAVA_OPTS="-XX:+UseZGC -Xms512m -Xmx1024m -XX:MaxRAMPercentage=75" COPY target/nursing-home.jar /app.jar ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]5.2 前端Nginx配置
server { listen 80; server_name yourdomain.com; gzip on; gzip_types text/plain application/javascript application/x-javascript text/css; location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; add_header Cache-Control "no-cache"; } location /api { proxy_pass http://backend:8080; proxy_set_header X-Real-IP $remote_addr; } }6. 常见问题排查手册
6.1 数据库连接池耗尽
现象:出现HikariPool-1 - Connection is not available错误
解决方案:
- 检查连接泄漏:
@Bean public HikariDataSource dataSource() { HikariConfig config = new HikariConfig(); config.setLeakDetectionThreshold(30000); // 30秒泄漏检测 // 其他配置... }- 优化连接数公式:
最大连接数 = (核心数 * 2) + 有效磁盘数6.2 Vue路由刷新404
根本原因:History模式需要服务端配合
修复方案(Spring Boot端):
@Controller public class FrontendController { @RequestMapping(value = {"/", "/{path:[^\\.]*}"}) public String forward() { return "forward:/index.html"; } }7. 二次开发建议
- 代码生成器使用:
# 生成病房管理模块 mvn mybatis-plus:generate -DtableName=ward -DmoduleName=ward- 扩展字段最佳实践:
- 使用JSON类型字段存储动态属性
- 创建单独的扩展表(ext_表名)关联主表
- 工作流引擎集成:
<!-- pom.xml添加 --> <dependency> <groupId>org.flowable</groupId> <artifactId>flowable-spring-boot-starter</artifactId> <version>6.7.2</version> </dependency>这套系统在实际运行中经历过单日500+并发访问的考验,核心接口平均响应时间保持在200ms以内。特别值得一提的是健康报告生成模块,通过引入POI-TL模板引擎,将PDF生成速度从原来的15秒优化到3秒内。建议初次接触医疗系统的开发者重点研究数据权限控制部分,我们实现的"部门+角色+个人"三级权限模型可以覆盖90%以上的业务场景。