)
SpringBootVue全栈实战慢性病健康管理平台开发全流程解析慢性病管理正成为医疗健康领域的重要议题而技术手段的介入让健康管理变得更加智能和便捷。今天我们将通过一个完整的项目案例手把手教你如何使用SpringBoot和Vue构建一个功能完善的慢性病健康管理平台。这个项目不仅涵盖了前后端分离开发的完整流程还整合了智能问答等AI功能适合有一定Java和JavaScript基础的开发者进阶学习。1. 项目架构设计与技术选型1.1 整体技术栈规划在开始编码之前合理的架构设计和技术选型至关重要。我们的平台采用前后端分离架构后端技术栈核心框架Spring Boot 2.7.x数据库MySQL 8.0ORM框架MyBatis-Plus安全框架Spring Security JWTAI集成阿里云通义大模型API其他Lombok、Hutool工具包前端技术栈核心框架Vue 3 Composition APIUI组件库Element Plus状态管理Pinia路由Vue Router 4HTTP客户端Axios提示技术选型时需考虑团队熟悉度、社区活跃度和长期维护性避免盲目追求新技术1.2 系统模块划分平台主要分为以下几个功能模块模块名称主要功能技术实现要点用户中心注册登录、权限管理JWT鉴权、RBAC模型健康档案患者基本信息管理表单验证、文件上传健康监测血糖/血压数据记录图表展示、数据导出健康评估风险评估报告生成算法模型集成随访管理医患互动记录消息通知系统健康咨询智能问答系统大模型API集成健康百科医学知识库富文本编辑与展示2. 后端核心实现2.1 SpringBoot项目初始化首先创建一个标准的SpringBoot项目spring init --dependenciesweb,mybatis-plus,mysql,security,lombok -g com.example -a chronic-disease-management chronic-disease-backend关键配置文件application.yml示例server: port: 8080 servlet: context-path: /api spring: datasource: url: jdbc:mysql://localhost:3306/chronic_db?useSSLfalseserverTimezoneUTC username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl global-config: db-config: logic-delete-field: delFlag # 逻辑删除字段 logic-delete-value: 1 # 删除值 logic-not-delete-value: 0 # 未删除值 jwt: secret: your-secret-key expiration: 86400000 # 24小时2.2 数据库设计与实现采用MySQL作为主数据库主要表结构设计如下用户表(tb_user)CREATE TABLE tb_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 真实姓名, gender char(1) DEFAULT 0 COMMENT 性别(0男 1女), birth_date date DEFAULT NULL COMMENT 出生日期, phone varchar(20) DEFAULT NULL COMMENT 手机号, user_type char(1) DEFAULT 0 COMMENT 用户类型(0患者 1医生), status char(1) DEFAULT 0 COMMENT 状态(0正常 1停用), del_flag char(1) DEFAULT 0 COMMENT 删除标志, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (user_id), UNIQUE KEY idx_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户信息表;血糖记录表(tb_blood_sugar)CREATE TABLE tb_blood_sugar ( record_id bigint NOT NULL AUTO_INCREMENT, user_id bigint NOT NULL COMMENT 用户ID, measure_time datetime NOT NULL COMMENT 测量时间, sugar_value decimal(4,1) NOT NULL COMMENT 血糖值(mmol/L), measure_type char(1) DEFAULT 0 COMMENT 测量类型(0空腹 1餐后), remark varchar(200) DEFAULT NULL COMMENT 备注, create_time datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (record_id), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT血糖记录表;使用MyBatis-Plus实现基础CRUD操作Service public class BloodSugarServiceImpl extends ServiceImplBloodSugarMapper, BloodSugar implements BloodSugarService { Override public PageBloodSugar getRecordsByUser(Long userId, DateRangeQuery query) { LambdaQueryWrapperBloodSugar wrapper new LambdaQueryWrapper(); wrapper.eq(BloodSugar::getUserId, userId) .between(BloodSugar::getMeasureTime, query.getStartDate(), query.getEndDate()) .orderByDesc(BloodSugar::getMeasureTime); return this.page(new Page(query.getPageNum(), query.getPageSize()), wrapper); } Override public SugarStatistics getStatistics(Long userId, String period) { // 实现统计逻辑 } }2.3 健康咨询模块集成大模型集成阿里云通义大模型实现智能问答Service public class HealthConsultServiceImpl implements HealthConsultService { Value(${aliyun.ai.access-key-id}) private String accessKeyId; Value(${aliyun.ai.access-key-secret}) private String accessKeySecret; Override public String getHealthAdvice(String question) { // 1. 数据清洗 String cleanedQuestion cleanQuestion(question); // 2. 调用大模型API DefaultProfile profile DefaultProfile.getProfile( cn-hangzhou, accessKeyId, accessKeySecret); IAcsClient client new DefaultAcsClient(profile); CommonRequest request new CommonRequest(); request.setSysDomain(nlp.cn-hangzhou.aliyuncs.com); request.setSysVersion(2020-06-29); request.setSysAction(GetHealthAdvice); request.putQueryParameter(Question, cleanedQuestion); try { CommonResponse response client.getCommonResponse(request); HealthAdviceResponse adviceResponse JSON.parseObject( response.getData(), HealthAdviceResponse.class); return adviceResponse.getAdvice(); } catch (Exception e) { throw new RuntimeException(获取健康建议失败, e); } } private String cleanQuestion(String question) { // 实现敏感词过滤、问题标准化等 } }3. 前端Vue3实现3.1 Vue项目初始化与配置使用Vite创建Vue3项目npm create vitelatest chronic-disease-frontend --template vue cd chronic-disease-frontend npm install element-plus axios pinia vue-router关键路由配置示例import { createRouter, createWebHistory } from vue-router const routes [ { path: /, component: () import(/layouts/MainLayout.vue), children: [ { path: , name: Home, component: () import(/views/HomeView.vue), meta: { requiresAuth: true } }, { path: blood-sugar, name: BloodSugar, component: () import(/views/monitor/BloodSugarView.vue), meta: { requiresAuth: true } }, { path: consult, name: HealthConsult, component: () import(/views/consult/ConsultView.vue), meta: { requiresAuth: true } } ] }, { path: /login, name: Login, component: () import(/views/auth/LoginView.vue) } ] const router createRouter({ history: createWebHistory(import.meta.env.BASE_URL), routes }) // 路由守卫 router.beforeEach((to, from, next) { const isAuthenticated localStorage.getItem(token) if (to.meta.requiresAuth !isAuthenticated) { next({ name: Login }) } else { next() } }) export default router3.2 血糖监测功能实现使用ECharts实现数据可视化script setup import { ref, onMounted } from vue import * as echarts from echarts import { getBloodSugarRecords } from /api/monitor const chartRef ref(null) const records ref([]) const loadData async () { const res await getBloodSugarRecords({ userId: 123, startDate: 2023-01-01, endDate: 2023-06-30 }) records.value res.data // 初始化图表 const chart echarts.init(chartRef.value) const option { tooltip: { trigger: axis, formatter: params { const data params[0].data return 日期: ${data.date}br/血糖值: ${data.value}mmol/L } }, xAxis: { type: category, data: records.value.map(item item.measureTime) }, yAxis: { type: value, name: 血糖值(mmol/L) }, series: [{ data: records.value.map(item ({ value: item.sugarValue, date: item.measureTime })), type: line, smooth: true, lineStyle: { width: 3, color: #409EFF } }] } chart.setOption(option) } onMounted(() { loadData() }) /script template div classcontainer div refchartRef stylewidth: 100%; height: 400px;/div el-table :datarecords stylewidth: 100% el-table-column propmeasureTime label测量时间 width180 / el-table-column propsugarValue label血糖值(mmol/L) width120 / el-table-column propmeasureType label测量类型 width120 template #default{row} {{ row.measureType 0 ? 空腹 : 餐后 }} /template /el-table-column el-table-column propremark label备注 / /el-table /div /template3.3 健康咨询模块实现实现与大模型的交互界面script setup import { ref } from vue import { postHealthConsult } from /api/consult const question ref() const answers ref([]) const loading ref(false) const submitQuestion async () { if (!question.value.trim()) return loading.value true try { const res await postHealthConsult({ question: question.value }) answers.value.unshift({ question: question.value, answer: res.data, time: new Date().toLocaleString() }) question.value } finally { loading.value false } } /script template div classconsult-container el-input v-modelquestion placeholder输入您的健康问题例如糖尿病患者适合吃什么水果 typetextarea :rows3 clearable / div classmt-3 text-right el-button typeprimary :loadingloading clicksubmitQuestion 提交咨询 /el-button /div div classanswer-list mt-5 el-card v-for(item, index) in answers :keyindex classmb-3 template #header div classflex justify-between span问题{{ item.question }}/span span classtext-gray-500 text-sm{{ item.time }}/span /div /template div classanswer-content v-htmlitem.answer/div /el-card /div /div /template style scoped .answer-content { line-height: 1.8; white-space: pre-wrap; } /style4. 系统部署与优化4.1 生产环境部署方案推荐使用Docker进行容器化部署后端DockerfileFROM openjdk:17-jdk-slim WORKDIR /app COPY target/chronic-disease-backend-0.0.1-SNAPSHOT.jar app.jar EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]前端DockerfileFROM nginx:alpine WORKDIR /usr/share/nginx/html COPY dist . COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80docker-compose.ymlversion: 3.8 services: backend: build: ./backend ports: - 8080:8080 environment: - SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/chronic_db - SPRING_DATASOURCE_USERNAMEroot - SPRING_DATASOURCE_PASSWORDyourpassword depends_on: - mysql frontend: build: ./frontend ports: - 80:80 depends_on: - backend mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORDyourpassword - MYSQL_DATABASEchronic_db volumes: - mysql_data:/var/lib/mysql ports: - 3306:3306 volumes: mysql_data:4.2 性能优化建议后端优化启用Spring Boot Actuator监控端点配置HikariCP连接池参数添加二级缓存Redis接口响应数据压缩异步处理耗时操作前端优化路由懒加载组件按需引入启用Gzip压缩配置合理的缓存策略使用CDN加速静态资源4.3 常见问题排查跨域问题Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOrigins(*) .allowedMethods(GET, POST, PUT, DELETE) .allowedHeaders(*) .maxAge(3600); } }JWT认证失败 检查点请求头是否正确添加Authorization: Bearer tokenToken是否过期签名密钥是否一致Token生成时是否包含了必要的claims大模型API调用失败检查AccessKey配置验证网络连接确认API服务可用性检查请求参数格式在实际开发中我们遇到了几个值得分享的经验点首先是前后端联调时的数据格式一致性建议使用Swagger或类似的API文档工具其次是状态管理Pinia的模块化设计非常适合这种中型应用最后是AI集成部分合理设计问答缓存机制可以显著提升用户体验。