1. 陪诊预约系统需求分析与技术选型
最近接了个医疗健康领域的项目需求,需要开发一套陪诊预约系统。这类系统在老龄化社会和就医陪护需求增长的背景下,市场潜力巨大。经过技术评估,我决定采用SpringBoot+Vue的前后端分离架构来实现。
选择SpringBoot作为后端框架主要基于三点考虑:一是其快速开发特性可以缩短项目周期;二是丰富的starter依赖能轻松整合MyBatis、Redis等常用组件;三是内嵌Tomcat简化部署。前端选用Vue.js则是因为其组件化开发模式特别适合这类交互复杂的后台管理系统,配合Element UI可以快速构建美观的界面。
从功能模块来看,系统需要包含:
- 用户角色管理(患者、陪诊员、管理员)
- 预约服务管理(时间选择、服务类型)
- 订单支付系统
- 评价反馈机制
- 即时通讯功能
提示:医疗健康类系统要特别注意用户隐私保护,建议在架构设计阶段就考虑数据加密方案,比如使用JWT进行身份认证,敏感字段采用AES加密存储。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心数据库设计与业务逻辑
2.1 数据库表结构设计
核心表包括用户表、服务类型表、订单表和评价表。用户表采用RBAC模型设计,通过角色字段区分患者、陪诊员和管理员:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '登录账号',
`password` varchar(100) NOT NULL COMMENT '加密密码',
`real_name` varchar(20) DEFAULT NULL COMMENT '真实姓名',
`phone` varchar(20) NOT NULL COMMENT '手机号',
`role` enum('patient','companion','admin') NOT NULL COMMENT '用户角色',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像URL',
`id_card` varchar(50) DEFAULT NULL COMMENT '身份证号(AES加密)',
`status` tinyint DEFAULT '1' COMMENT '状态(0禁用1正常)',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`),
KEY `idx_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
订单表设计需要考虑状态流转,典型状态包括:
- 待支付
- 已预约
- 服务中
- 已完成
- 已取消
- 已退款
2.2 预约业务状态机实现
使用Spring StateMachine实现订单状态管理是较好的选择。首先定义状态和事件枚举:
java复制public enum OrderStates {
UNPAID, // 待支付
APPOINTED, // 已预约
IN_SERVICE, // 服务中
COMPLETED, // 已完成
CANCELLED, // 已取消
REFUNDED // 已退款
}
public enum OrderEvents {
PAY, // 支付
CANCEL, // 取消
START, // 开始服务
FINISH, // 完成服务
REFUND // 退款
}
然后配置状态转换规则:
java复制@Configuration
@EnableStateMachineFactory
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states)
throws Exception {
states
.withStates()
.initial(OrderStates.UNPAID)
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions)
throws Exception {
transitions
.withExternal()
.source(OrderStates.UNPAID).target(OrderStates.APPOINTED)
.event(OrderEvents.PAY)
.and()
.withExternal()
.source(OrderStates.UNPAID).target(OrderStates.CANCELLED)
.event(OrderEvents.CANCEL)
// 其他状态转换规则...
}
}
3. 前后端分离架构实现
3.1 SpringBoot后端关键实现
采用三层架构设计:
- Controller层:处理HTTP请求,参数校验
- Service层:业务逻辑实现
- DAO层:数据持久化
RESTful API设计示例(预约相关):
java复制@RestController
@RequestMapping("/api/appointments")
public class AppointmentController {
@Autowired
private AppointmentService appointmentService;
@PostMapping
public Result createAppointment(@Valid @RequestBody CreateAppointmentDTO dto) {
return Result.success(appointmentService.createAppointment(dto));
}
@GetMapping("/{id}")
public Result getAppointmentDetail(@PathVariable Long id) {
return Result.success(appointmentService.getDetail(id));
}
@PutMapping("/{id}/cancel")
public Result cancelAppointment(@PathVariable Long id) {
return Result.success(appointmentService.cancelAppointment(id));
}
}
3.2 Vue前端工程结构
前端项目采用Vue CLI搭建,典型目录结构:
code复制src/
├── api/ # 接口定义
├── assets/ # 静态资源
├── components/ # 公共组件
├── router/ # 路由配置
├── store/ # Vuex状态管理
├── utils/ # 工具函数
├── views/ # 页面组件
│ ├── appointment/ # 预约相关页面
│ ├── user/ # 用户中心
│ └── ...
├── App.vue
└── main.js
使用Axios进行HTTP请求封装,示例:
javascript复制// api/appointment.js
import request from '@/utils/request'
export function createAppointment(data) {
return request({
url: '/api/appointments',
method: 'post',
data
})
}
// 在Vue组件中使用
import { createAppointment } from '@/api/appointment'
export default {
methods: {
async submitForm() {
try {
const res = await createAppointment(this.form)
this.$message.success('预约成功')
} catch (error) {
this.$message.error(error.message)
}
}
}
}
4. 系统安全与性能优化
4.1 安全防护措施
-
认证与授权:
- 使用JWT进行无状态认证
- 接口权限通过注解控制:
java复制@PreAuthorize("hasRole('patient')") @PostMapping public Result createAppointment(...) { ... }
-
数据安全:
- 敏感字段加密存储(如身份证号)
- SQL注入防护:MyBatis使用#{}参数绑定
- XSS防护:前端使用vue-sanitize处理富文本
-
接口防刷:
- 使用Guava RateLimiter实现限流
- 关键操作增加短信验证码校验
4.2 性能优化方案
-
缓存策略:
- 使用Redis缓存热门服务类型、陪诊员信息
- 本地缓存(Caffeine)缓存不常变的配置数据
-
数据库优化:
- 为常用查询字段建立索引
- 大表考虑分库分表(如订单表按用户ID分片)
-
前端优化:
- 路由懒加载
- 组件异步加载
- 使用keep-alive缓存页面状态
注意:医疗类系统要特别注意高并发场景下的预约冲突问题,建议使用乐观锁或分布式锁处理:
java复制@Transactional public boolean createAppointment(CreateAppointmentDTO dto) { // 使用SELECT...FOR UPDATE获取悲观锁 Companion companion = companionMapper.selectForUpdate(dto.getCompanionId()); if (companion.getAvailableSlots() <= 0) { throw new BusinessException("该时段已约满"); } // 更新可用名额 companionMapper.reduceAvailableSlots(dto.getCompanionId()); // 创建预约记录... }
5. 典型问题排查与解决
在实际开发中遇到几个典型问题值得分享:
-
跨域问题:
- 现象:前端请求报CORS错误
- 解决:后端添加CORS配置
java复制@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("*") .allowedHeaders("*"); } }
-
文件上传大小限制:
- 现象:上传大文件时报错
- 解决:调整SpringBoot配置
yaml复制spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB
-
Vue路由刷新404:
- 现象:生产环境刷新页面报404
- 解决:Nginx配置重定向
code复制location / { try_files $uri $uri/ /index.html; }
-
时间格式问题:
- 现象:前端显示的时间与后端不一致
- 解决:统一使用UTC时间传输,前端做本地化转换
javascript复制// 使用day.js处理时间 import dayjs from 'dayjs' const localTime = dayjs(utcTime).format('YYYY-MM-DD HH:mm')
6. 部署与监控方案
6.1 容器化部署
使用Docker Compose编排服务:
yaml复制version: '3'
services:
backend:
build: ./backend
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=appointment
volumes:
- mysql_data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
mysql_data:
6.2 监控与日志
-
SpringBoot监控:
- 集成Actuator暴露健康检查端点
- 使用Prometheus收集指标
- Grafana可视化监控数据
-
前端监控:
- 使用Sentry捕获前端错误
- 接入Google Analytics分析用户行为
-
日志管理:
- 使用ELK(Elasticsearch+Logstash+Kibana)栈集中管理日志
- 关键业务操作记录审计日志
java复制// 审计日志切面示例
@Aspect
@Component
public class AuditLogAspect {
@Autowired
private AuditLogService auditLogService;
@AfterReturning(pointcut = "@annotation(auditLog)", returning = "result")
public void afterReturning(JoinPoint joinPoint, AuditLog auditLog, Object result) {
String operation = auditLog.value();
// 获取当前用户
User user = SecurityUtils.getCurrentUser();
// 保存审计日志
auditLogService.saveLog(user, operation, joinPoint.getArgs(), result);
}
}
这套系统从设计到实现大约需要2-3周开发时间,关键点在于预约状态的精确管理和并发控制。在实际开发中,建议使用Swagger进行API文档管理,利用Jenkins搭建CI/CD流水线提高交付效率。对于初期版本,可以优先实现核心预约功能,后续再迭代评价系统和即时通讯模块。
