1. 项目概述与背景
在公共卫生管理领域,疫苗接种一直是预防疾病传播的重要手段。特别是在经历了全球性健康事件后,高效、便捷的疫苗接种管理变得尤为重要。传统依靠人工登记、电话预约和纸质通知的方式,在接种高峰期经常面临信息错漏、排队拥堵、资源分配不均等问题。
作为一名长期从事医疗信息化系统开发的工程师,我深刻理解基层医护人员在疫苗接种管理中的痛点:重复录入工作量大、预约信息核对耗时、接种提醒依赖人工记忆等。这些问题不仅增加了工作负担,也影响了居民的接种体验。
基于Spring Boot框架开发的社区疫苗预约与接种管理平台,正是为了解决这些实际问题而生。这个系统将疫苗档案管理、预约登记、接种提醒、取消处理、科普宣传等全流程线上化,实现了"数据多跑路,群众少等待"的目标。通过近半年的实际开发和测试,系统已经能够稳定运行,显著提升了疫苗接种管理效率。
2. 系统架构设计
2.1 技术选型与架构模式
系统采用标准的B/S三层架构设计,这种架构选择主要基于以下考虑:
-
表现层:使用Vue.js框架构建响应式前端界面,确保在不同设备上都能提供良好的用户体验。Vue的组件化开发模式也便于功能模块的复用和维护。
-
业务层:基于Spring Boot框架开发后端服务。Spring Boot的自动配置和起步依赖特性大大简化了项目配置,其内置的Tomcat服务器也方便了应用的部署和运行。
-
持久层:采用MyBatis作为ORM框架,配合MySQL 5.7数据库。MyBatis的灵活性使得我们可以编写复杂的SQL查询,同时保持代码的可维护性。
提示:在实际开发中,我们选择了MySQL 5.7而非8.0版本,主要考虑到5.7版本在企业环境中部署更广泛,且对硬件资源要求更低,适合中小型医疗机构使用。
2.2 核心功能模块划分
系统功能模块设计遵循"高内聚、低耦合"原则,主要划分为以下几个核心模块:
-
疫苗信息管理模块:负责疫苗基础信息的维护和展示,包括疫苗类型、属性、库存等。
-
预约管理模块:处理用户的预约申请、取消请求以及预约审核流程。
-
接种提醒模块:自动计算并推送下一针接种时间提醒,支持多种通知方式。
-
科普宣传模块:提供疫苗相关知识的发布、展示和互动功能。
-
统计分析模块:生成各类接种数据报表,辅助管理决策。
-
系统管理模块:处理用户权限、系统参数等基础配置。
这种模块化设计不仅便于团队分工协作,也使得系统在未来可以灵活扩展新功能。
3. 数据库设计与实现
3.1 数据库概念模型
系统数据库设计采用了实体-关系模型,主要包含以下核心实体:
-
用户实体(User):存储系统用户的基本信息,区分管理员和普通用户角色。
-
疫苗实体(Vaccine):记录疫苗的详细属性,包括名称、类型、生产信息等。
-
预约实体(Appointment):管理用户的预约记录,关联用户和疫苗信息。
-
提醒实体(Reminder):存储接种提醒信息,与预约记录相关联。
这些实体之间的关系通过外键约束来维护,确保数据的完整性和一致性。例如,一个用户可以有多条预约记录,但每条预约记录必须关联一个有效的用户ID和疫苗ID。
3.2 关键表结构设计
以下是几个核心表的结构设计:
- vaccine_info表:
sql复制CREATE TABLE `vaccine_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '疫苗名称',
`type_id` int(11) NOT NULL COMMENT '疫苗类型ID',
`manufacturer` varchar(100) DEFAULT NULL COMMENT '生产厂家',
`batch_number` varchar(50) DEFAULT NULL COMMENT '批号',
`production_date` date DEFAULT NULL COMMENT '生产日期',
`expiry_date` date DEFAULT NULL COMMENT '有效期至',
`stock` int(11) NOT NULL DEFAULT '0' COMMENT '库存数量',
`price` decimal(10,2) DEFAULT NULL COMMENT '价格',
`contraindications` text COMMENT '禁忌症',
`location_id` int(11) DEFAULT NULL COMMENT '接种地点ID',
`click_count` int(11) DEFAULT '0' COMMENT '点击量',
`collect_count` int(11) DEFAULT '0' COMMENT '收藏数',
PRIMARY KEY (`id`),
KEY `idx_type` (`type_id`),
KEY `idx_location` (`location_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='疫苗信息表';
- appointment表:
sql复制CREATE TABLE `appointment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL COMMENT '用户ID',
`vaccine_id` int(11) NOT NULL COMMENT '疫苗ID',
`appointment_time` datetime NOT NULL COMMENT '预约时间',
`location_id` int(11) NOT NULL COMMENT '接种地点ID',
`quantity` int(11) NOT NULL DEFAULT '1' COMMENT '预约数量',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0-待审核 1-已通过 2-已拒绝',
`payment_status` tinyint(4) DEFAULT '0' COMMENT '支付状态',
`cancel_reason` varchar(255) DEFAULT NULL COMMENT '取消原因',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `idx_user` (`user_id`),
KEY `idx_vaccine` (`vaccine_id`),
KEY `idx_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='预约记录表';
注意:在设计数据库时,我们特别注意了索引的合理使用。对于经常作为查询条件的字段(如user_id、vaccine_id、status等)都建立了索引,以提升查询性能。但同时也要避免过度索引,因为索引会占用存储空间并影响写入性能。
4. 核心功能实现细节
4.1 预约流程实现
疫苗接种预约是系统的核心功能之一,其实现流程如下:
-
疫苗选择:用户在前端浏览疫苗列表,系统会实时显示各疫苗的库存状态和可预约时段。
-
时段选择:基于接种点的承载量配置,系统动态计算并展示可预约时段,避免过度预约导致的拥挤。
-
预约提交:用户填写必要信息后提交预约请求,系统会执行以下验证:
- 疫苗库存是否充足
- 用户是否已达到该疫苗的最大预约次数
- 预约时段是否仍有空位
-
支付处理:支持在线支付和到院支付两种方式,支付完成后预约状态更新为"已确认"。
-
通知发送:系统自动向用户发送预约成功通知,包含预约详情和注意事项。
后端核心代码示例(Java):
java复制@RestController
@RequestMapping("/api/appointment")
public class AppointmentController {
@Autowired
private AppointmentService appointmentService;
@PostMapping
public ResponseEntity<?> createAppointment(@RequestBody AppointmentDTO dto) {
// 验证预约数据有效性
if (!appointmentService.validateAppointment(dto)) {
return ResponseEntity.badRequest().body("无效的预约请求");
}
// 检查库存
if (!appointmentService.checkVaccineStock(dto.getVaccineId(), dto.getQuantity())) {
return ResponseEntity.badRequest().body("疫苗库存不足");
}
// 创建预约记录
Appointment appointment = appointmentService.createAppointment(dto);
// 扣减库存
appointmentService.updateVaccineStock(dto.getVaccineId(), -dto.getQuantity());
// 发送通知
notificationService.sendAppointmentConfirmation(appointment.getUserId(), appointment);
return ResponseEntity.ok(appointment);
}
}
4.2 接种提醒功能
系统会根据疫苗的接种规则自动计算下一针时间,并提前发送提醒。实现要点包括:
-
规则配置:每种疫苗可以配置不同的接种规则(如间隔天数、固定日期等)。
-
自动计算:基于用户已完成接种记录,计算下次应接种时间。
-
多渠道通知:支持站内消息、短信、邮件等多种提醒方式。
-
手动补录:对于特殊情况下的接种,支持医护人员手动补录并重新计算提醒时间。
提醒服务核心逻辑:
java复制@Service
public class ReminderServiceImpl implements ReminderService {
@Scheduled(cron = "0 0 9 * * ?") // 每天上午9点执行
public void generateDailyReminders() {
// 查询今天需要发送提醒的预约记录
List<Appointment> appointments = appointmentRepository
.findByNextDoseDate(LocalDate.now());
for (Appointment app : appointments) {
Reminder reminder = new Reminder();
reminder.setUserId(app.getUserId());
reminder.setVaccineId(app.getVaccineId());
reminder.setReminderTime(LocalDateTime.now());
reminder.setDoseNumber(app.getDoseNumber() + 1);
reminder.setStatus(ReminderStatus.PENDING);
reminderRepository.save(reminder);
// 异步发送通知
notificationService.sendReminder(app.getUserId(), reminder);
}
}
}
5. 系统安全与性能优化
5.1 安全防护措施
-
认证与授权:采用Spring Security框架实现基于角色的访问控制,确保用户只能访问其权限范围内的功能。
-
数据加密:敏感信息如用户身份证号、联系方式等采用AES加密存储,即使数据库泄露也无法直接获取明文。
-
防SQL注入:使用MyBatis的参数化查询,避免拼接SQL语句导致的安全风险。
-
日志审计:记录关键操作日志,便于事后追溯和分析。
安全配置示例:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/public/**").permitAll()
.antMatchers("/api/admin/**").hasRole("ADMIN")
.antMatchers("/api/user/**").hasAnyRole("USER", "ADMIN")
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
}
5.2 性能优化策略
-
缓存应用:使用Redis缓存热点数据,如疫苗列表、接种点信息等,减轻数据库压力。
-
异步处理:将通知发送、报表生成等耗时操作异步化,提升接口响应速度。
-
数据库优化:合理设计索引,定期执行表优化和统计信息更新。
-
前端懒加载:对于大量数据的列表页面,采用分页和懒加载技术优化用户体验。
缓存配置示例:
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
@Service
public class VaccineServiceImpl implements VaccineService {
@Cacheable(value = "vaccines", key = "#typeId")
public List<Vaccine> getVaccinesByType(Integer typeId) {
// 数据库查询逻辑
return vaccineRepository.findByTypeId(typeId);
}
}
6. 系统部署与运维
6.1 环境要求与部署步骤
系统部署需要满足以下环境要求:
-
服务器配置:
- CPU:至少4核
- 内存:8GB以上
- 磁盘空间:50GB以上(根据数据量调整)
- 操作系统:Linux(推荐CentOS 7+或Ubuntu 18.04+)
-
软件依赖:
- JDK 1.8+
- MySQL 5.7+
- Redis(用于缓存)
- Nginx(反向代理和负载均衡)
部署流程:
- 安装基础环境(JDK、MySQL、Redis等)
- 创建数据库并导入初始数据
- 打包应用(使用Maven或Gradle)
- 配置应用属性(数据库连接、Redis配置等)
- 启动应用服务
- 配置Nginx反向代理
6.2 日常运维建议
-
监控设置:配置系统健康检查接口,监控服务可用性和性能指标。
-
日志管理:定期归档和分析日志文件,使用ELK等工具建立集中式日志管理系统。
-
备份策略:制定数据库定期备份计划,测试备份恢复流程。
-
性能调优:根据监控数据持续优化系统性能,如调整JVM参数、优化SQL查询等。
健康检查接口示例:
java复制@RestController
@RequestMapping("/actuator")
public class HealthController {
@GetMapping("/health")
public ResponseEntity<?> healthCheck() {
Map<String, Object> health = new HashMap<>();
health.put("status", "UP");
health.put("timestamp", System.currentTimeMillis());
return ResponseEntity.ok(health);
}
@GetMapping("/db-check")
public ResponseEntity<?> dbHealthCheck() {
try {
// 执行简单查询测试数据库连接
jdbcTemplate.queryForObject("SELECT 1", Integer.class);
return ResponseEntity.ok(Collections.singletonMap("status", "OK"));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(Collections.singletonMap("error", "Database connection failed"));
}
}
}
7. 开发经验与心得
在实际开发过程中,我们积累了一些宝贵的经验教训:
-
需求明确是关键:在项目初期,我们花费了大量时间与医疗机构沟通,明确他们的实际工作流程和痛点。这帮助我们避免了后期频繁的需求变更。
-
测试驱动开发:对于核心功能如预约逻辑,我们采用了测试驱动开发(TDD)的方式,先编写测试用例再实现功能,这显著提高了代码质量和可靠性。
-
性能考虑要前置:在数据库设计阶段就考虑性能优化,如合理分表、建立适当索引等,比后期再优化要高效得多。
-
用户体验至关重要:即使是后台管理系统,也要注重操作流程的简洁性和一致性。我们通过多次原型评审和用户测试,不断优化界面交互。
-
文档同步更新:随着代码的迭代,保持文档的同步更新。我们使用Swagger自动生成API文档,确保接口文档始终与代码一致。
一个特别值得分享的技巧是关于并发预约的处理:
java复制@Service
public class AppointmentServiceImpl implements AppointmentService {
@Transactional
public Appointment createAppointment(AppointmentDTO dto) {
// 使用SELECT FOR UPDATE加锁,防止超卖
Vaccine vaccine = vaccineRepository.findByIdWithLock(dto.getVaccineId());
if (vaccine.getStock() < dto.getQuantity()) {
throw new BusinessException("疫苗库存不足");
}
// 扣减库存
vaccine.setStock(vaccine.getStock() - dto.getQuantity());
vaccineRepository.save(vaccine);
// 创建预约记录
Appointment appointment = convertToEntity(dto);
return appointmentRepository.save(appointment);
}
}
这段代码中,我们使用了数据库的悲观锁机制(SELECT FOR UPDATE)来确保在高并发场景下不会出现库存超卖的问题。这是电商系统中常见的技巧,同样适用于疫苗接种预约场景。