1. 项目概述
社区健康管理系统是基于SpringBoot+Vue技术栈开发的一款面向社区医疗机构和居民的健康管理平台。作为一名有10年全栈开发经验的工程师,我在实际开发过程中发现这类系统能够有效解决传统社区健康管理中存在的信息孤岛、服务效率低下等问题。
这个系统采用了前后端分离的架构设计,后端使用SpringBoot框架提供RESTful API接口,前端采用Vue.js构建用户界面,数据库选用MySQL进行数据存储。系统主要包含用户管理、健康档案、预约挂号、健康咨询等核心功能模块。
提示:在开始开发前,建议先梳理清楚社区健康管理的业务流程,明确不同角色(管理员、医生、居民)的操作权限和功能需求。
2. 技术架构设计
2.1 后端技术栈
后端采用SpringBoot作为基础框架,这是我经过多个项目验证后的选择。SpringBoot的自动配置特性可以大幅减少XML配置,内嵌Tomcat服务器也简化了部署流程。在实际开发中,我特别推荐使用以下依赖:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
MyBatis-Plus是我特别推荐使用的ORM框架,它基于MyBatis进行了增强,提供了很多开箱即用的功能,比如:
- 通用CRUD操作
- 分页插件
- 性能分析插件
- 乐观锁插件
2.2 前端技术栈
前端采用Vue.js 3.x版本,配合Element Plus组件库。这种组合在实际项目中表现非常出色:
- Vue 3的Composition API让代码组织更清晰
- Element Plus提供了丰富的UI组件,加速开发
- Axios处理HTTP请求
- Vue Router管理路由
- Pinia/Vuex进行状态管理
javascript复制// 典型的前端项目结构
src/
├── api/ // API请求封装
├── assets/ // 静态资源
├── components/ // 公共组件
├── router/ // 路由配置
├── store/ // 状态管理
├── utils/ // 工具函数
└── views/ // 页面组件
2.3 数据库设计
数据库设计是系统稳定性的关键。根据社区健康管理的特点,我设计了以下核心表:
- 用户表(sys_user):存储系统用户信息
- 角色表(sys_role):定义用户角色
- 健康档案表(health_record):居民健康信息
- 预约表(appointment):挂号预约信息
- 咨询表(consultation):健康咨询记录
sql复制CREATE TABLE `sys_user` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) NOT NULL COMMENT '密码',
`real_name` varchar(50) DEFAULT NULL COMMENT '真实姓名',
`phone` varchar(20) DEFAULT NULL COMMENT '手机号',
`gender` tinyint DEFAULT NULL COMMENT '性别(0:未知 1:男 2:女)',
`birth_date` date DEFAULT NULL COMMENT '出生日期',
`address` varchar(200) DEFAULT NULL COMMENT '住址',
`status` tinyint DEFAULT '1' COMMENT '状态(0:禁用 1:正常)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
3. 核心功能实现
3.1 用户认证与授权
系统采用JWT(JSON Web Token)进行认证,这是我经过多个项目验证的可靠方案。相比传统的Session认证,JWT更适合前后端分离架构:
- 无状态,服务端不需要存储Session
- 可扩展性强,适合分布式系统
- 安全性高,配合HTTPS使用更安全
后端实现代码示例:
java复制@RestController
@RequestMapping("/auth")
public class AuthController {
@Autowired
private UserService userService;
@Autowired
private JwtTokenProvider jwtTokenProvider;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
// 验证用户名密码
User user = userService.authenticate(request.getUsername(), request.getPassword());
// 生成Token
String token = jwtTokenProvider.generateToken(user);
// 返回Token和用户基本信息
Map<String, Object> response = new HashMap<>();
response.put("token", token);
response.put("user", new UserDto(user));
return ResponseEntity.ok(response);
}
}
前端需要在axios拦截器中添加Token:
javascript复制// 请求拦截器
axios.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
}, error => {
return Promise.reject(error)
})
3.2 健康档案管理
健康档案是系统的核心功能,我设计了详细的数据结构和业务逻辑:
- 基本信息:个人基础健康数据
- 病史记录:既往病史、家族病史
- 体检记录:历次体检结果
- 用药记录:长期用药情况
后端接口示例:
java复制@RestController
@RequestMapping("/api/health-records")
public class HealthRecordController {
@Autowired
private HealthRecordService healthRecordService;
@GetMapping("/{userId}")
public ResponseEntity<HealthRecord> getByUserId(@PathVariable Long userId) {
HealthRecord record = healthRecordService.getByUserId(userId);
return ResponseEntity.ok(record);
}
@PostMapping
public ResponseEntity<?> createOrUpdate(@RequestBody HealthRecord record) {
HealthRecord saved = healthRecordService.saveOrUpdate(record);
return ResponseEntity.ok(saved);
}
@GetMapping("/{userId}/history")
public ResponseEntity<List<HealthHistory>> getHistory(@PathVariable Long userId) {
List<HealthHistory> history = healthRecordService.getHistory(userId);
return ResponseEntity.ok(history);
}
}
3.3 预约挂号系统
预约挂号功能需要考虑以下几个关键点:
- 医生排班管理
- 号源生成规则
- 预约冲突检测
- 预约取消机制
我采用乐观锁解决并发预约问题:
java复制@Service
public class AppointmentServiceImpl implements AppointmentService {
@Autowired
private AppointmentMapper appointmentMapper;
@Transactional
public Appointment createAppointment(AppointmentDTO dto) {
// 检查号源是否可用
DoctorSchedule schedule = doctorScheduleService.getById(dto.getScheduleId());
if (schedule.getRemainCount() <= 0) {
throw new BusinessException("该时段号源已满");
}
// 使用乐观锁更新号源
int updated = doctorScheduleService.reduceRemainCount(dto.getScheduleId(), schedule.getVersion());
if (updated == 0) {
throw new ConcurrentModificationException("号源已被其他用户占用");
}
// 创建预约记录
Appointment appointment = new Appointment();
// 设置属性...
appointmentMapper.insert(appointment);
return appointment;
}
}
4. 系统部署与优化
4.1 部署方案
我推荐使用Docker容器化部署,这是目前最主流的部署方式:
- 后端服务打包为JAR,使用Dockerfile构建镜像
- 前端构建静态资源,使用Nginx作为Web服务器
- MySQL数据库单独部署,建议使用云数据库服务
- Redis用于缓存和Session共享
后端Dockerfile示例:
dockerfile复制FROM openjdk:11-jre-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
4.2 性能优化
在实际项目中,我总结了以下优化经验:
-
数据库优化:
- 合理设计索引
- 使用连接池(HikariCP)
- 读写分离(主从复制)
-
缓存策略:
- 热点数据使用Redis缓存
- 合理设置缓存过期时间
- 使用缓存注解简化开发
java复制@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private RedisTemplate<String, User> redisTemplate;
@Cacheable(value = "user", key = "#userId")
public User getById(Long userId) {
return userMapper.selectById(userId);
}
@CachePut(value = "user", key = "#user.userId")
public User update(User user) {
userMapper.updateById(user);
return user;
}
@CacheEvict(value = "user", key = "#userId")
public void delete(Long userId) {
userMapper.deleteById(userId);
}
}
- 前端优化:
- 组件懒加载
- 路由懒加载
- 合理使用keep-alive
- 图片等静态资源CDN加速
5. 常见问题与解决方案
5.1 跨域问题
前后端分离项目常见的跨域问题,我通常这样解决:
- 后端配置CORS:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.maxAge(3600);
}
}
- 前端开发环境配置代理:
javascript复制// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
5.2 文件上传
健康管理系统经常需要上传体检报告等文件,我采用以下方案:
- 后端接收文件:
java复制@RestController
@RequestMapping("/api/files")
public class FileController {
@PostMapping("/upload")
public ResponseEntity<FileInfo> upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
throw new BusinessException("请选择要上传的文件");
}
// 生成唯一文件名
String originalFilename = file.getOriginalFilename();
String fileExt = originalFilename.substring(originalFilename.lastIndexOf("."));
String fileName = UUID.randomUUID().toString() + fileExt;
// 保存文件
Path path = Paths.get("/upload", fileName);
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
// 返回文件信息
FileInfo fileInfo = new FileInfo();
fileInfo.setName(originalFilename);
fileInfo.setUrl("/upload/" + fileName);
fileInfo.setSize(file.getSize());
return ResponseEntity.ok(fileInfo);
}
}
- 前端使用Element Upload组件:
vue复制<template>
<el-upload
action="/api/files/upload"
:on-success="handleSuccess"
:before-upload="beforeUpload">
<el-button type="primary">点击上传</el-button>
</el-upload>
</template>
<script>
export default {
methods: {
beforeUpload(file) {
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
this.$message.error('文件大小不能超过10MB');
return false;
}
return true;
},
handleSuccess(response) {
this.$emit('uploaded', response.data);
}
}
}
</script>
5.3 数据导出
社区健康管理系统经常需要导出健康数据报表,我使用Apache POI实现:
java复制@Service
public class ExportServiceImpl implements ExportService {
public void exportHealthRecords(Long communityId, HttpServletResponse response) {
// 查询数据
List<HealthRecord> records = healthRecordService.getByCommunityId(communityId);
// 创建Excel工作簿
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("健康档案");
// 创建表头
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("姓名");
headerRow.createCell(1).setCellValue("性别");
headerRow.createCell(2).setCellValue("年龄");
// 其他表头...
// 填充数据
int rowNum = 1;
for (HealthRecord record : records) {
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(record.getUser().getRealName());
row.createCell(1).setCellValue(record.getUser().getGender() == 1 ? "男" : "女");
row.createCell(2).setCellValue(calculateAge(record.getUser().getBirthDate()));
// 其他数据...
}
// 设置响应头
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=health_records.xlsx");
// 写入响应流
workbook.write(response.getOutputStream());
workbook.close();
}
private int calculateAge(LocalDate birthDate) {
return Period.between(birthDate, LocalDate.now()).getYears();
}
}
6. 项目扩展方向
在实际开发中,我发现社区健康管理系统还可以进一步扩展以下功能:
-
健康数据分析:
- 使用ECharts实现健康数据可视化
- 基于机器学习算法进行健康风险评估
- 慢性病发展趋势预测
-
移动端接入:
- 开发微信小程序版本
- 对接智能穿戴设备数据
- 推送健康提醒和报告
-
多机构协作:
- 实现社区医院与三甲医院的数据互通
- 远程会诊功能
- 双向转诊系统
-
健康知识库:
- 疾病百科
- 健康食谱推荐
- 运动指导方案
在开发这类系统时,我特别注重以下几点:
- 数据安全性:健康数据属于敏感信息,必须做好加密和权限控制
- 系统稳定性:医疗系统对稳定性要求极高,需要完善的监控和容错机制
- 用户体验:考虑到用户年龄跨度大,界面设计要简洁明了,操作流程要简单
- 扩展性:预留接口,方便未来与其他医疗系统对接
这个项目我从零开始开发到最终上线大约用了3个月时间,期间遇到了不少挑战,比如如何处理高并发预约、如何保证健康数据的准确性等。通过这个项目,我积累了丰富的医疗健康领域开发经验,也总结出了一套适合这类系统的开发模式。