温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片!
1. 项目背景与目标
随着人们健康意识的不断提升,日常饮食管理逐渐成为大众关注的重点。然而,多数人在记录饮食时缺乏系统化的工具支撑,难以直观了解自身营养摄入是否均衡。本项目基于 SpringBoot 与 Vue3 构建一套健康饮食记录与分析系统,帮助用户便捷记录每日三餐与加餐,并通过可视化分析掌握热量、蛋白质、脂肪、碳水化合物等关键营养指标的摄入情况。
系统面向普通用户与健康管理场景,核心目标包括:
- 提供简洁高效的饮食记录入口,支持按餐次、时间、食物名称快速录入。
- 内置常见食物营养数据库,自动计算单次摄入的营养成分。
- 以图表形式展示每日、每周、每月的营养摄入趋势,辅助用户调整饮食结构。
- 支持个人目标设定,如每日热量预算、蛋白质目标等,并给出达成度提示。
2. 技术选型
系统采用前后端分离架构,后端基于 SpringBoot 提供 RESTful API,前端基于 Vue3 与 Element Plus 构建交互界面,数据存储使用 MySQL 数据库。
| 层次 | 技术栈 | 说明 |
|---|---|---|
| 后端框架 | SpringBoot 2.7 / 3.x | 提供业务接口、鉴权与数据持久化 |
| ORM | MyBatis-Plus | 简化数据库操作,提升开发效率 |
| 前端框架 | Vue3 + Vite | 组件化开发,组合式 API 管理状态 |
| UI 组件库 | Element Plus | 表格、表单、图表等基础组件 |
| 图表库 | ECharts | 营养摄入趋势与占比可视化 |
| 数据库 | MySQL 8.0 | 存储用户、食物、饮食记录等数据 |
| 鉴权方案 | JWT + Spring Security | 无状态登录认证与接口权限控制 |
3. 系统功能模块
系统整体划分为用户管理、食物管理、饮食记录、营养分析与目标管理五大核心模块。
3.1 用户管理
支持用户注册、登录与个人信息维护。登录成功后签发 JWT 令牌,前端在请求头中携带令牌访问受保护接口。用户可维护身高、体重、年龄、活动等级等基础信息,用于后续热量需求估算。
3.2 食物管理
内置常见食物营养数据库,管理员可维护食物名称、分类、单位以及每 100 克对应的热量、蛋白质、脂肪、碳水化合物等数据。用户也可自定义添加个人常用食物,便于快速录入。
3.3 饮食记录
用户按早餐、午餐、晚餐、加餐四个餐次记录每日饮食。每条记录关联食物与食用量,系统自动根据食物营养数据计算该条记录的热量与各营养素数值。记录支持按日期范围查询与修改删除。
3.4 营养分析
基于饮食记录数据,系统以折线图展示每日热量与三大营养素摄入趋势,以饼图展示蛋白质、脂肪、碳水化合物的供能占比,帮助用户直观判断饮食结构是否合理。
3.5 目标管理
用户可设定每日热量预算与蛋白质目标。系统根据当日实际摄入自动计算达成率,并在首页以进度条形式展示,辅助用户进行饮食调整。
4. 数据库设计
系统核心数据表包括用户表、食物表、饮食记录表与目标表。以下为主要表结构说明。
4.1 用户表 user
CREATE TABLE `user` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(50) NOT NULL COMMENT '用户名', `password` varchar(100) NOT NULL COMMENT '加密密码', `nickname` varchar(50) DEFAULT NULL COMMENT '昵称', `gender` tinyint DEFAULT NULL COMMENT '性别 1男 2女', `height` decimal(5,2) DEFAULT NULL COMMENT '身高cm', `weight` decimal(5,2) DEFAULT NULL COMMENT '体重kg', `age` int DEFAULT NULL COMMENT '年龄', `activity_level` tinyint DEFAULT NULL COMMENT '活动等级 1-5', `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;4.2 食物表 food
CREATE TABLE `food` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(50) NOT NULL COMMENT '食物名称', `category` varchar(20) DEFAULT NULL COMMENT '分类', `calorie` decimal(8,2) DEFAULT NULL COMMENT '热量kcal/100g', `protein` decimal(8,2) DEFAULT NULL COMMENT '蛋白质g/100g', `fat` decimal(8,2) DEFAULT NULL COMMENT '脂肪g/100g', `carbohydrate` decimal(8,2) DEFAULT NULL COMMENT '碳水g/100g', `user_id` bigint DEFAULT NULL COMMENT '自定义用户id,空为系统内置', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;4.3 饮食记录表 diet_record
CREATE TABLE `diet_record` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL COMMENT '用户id', `food_id` bigint NOT NULL COMMENT '食物id', `meal_type` tinyint NOT NULL COMMENT '餐次 1早餐 2午餐 3晚餐 4加餐', `amount` decimal(8,2) NOT NULL COMMENT '食用量g', `record_date` date NOT NULL COMMENT '记录日期', `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;4.4 目标表 goal
CREATE TABLE `goal` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL COMMENT '用户id', `daily_calorie` decimal(8,2) DEFAULT NULL COMMENT '每日热量目标', `daily_protein` decimal(8,2) DEFAULT NULL COMMENT '每日蛋白质目标g', `update_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;5. 后端核心实现
后端采用分层架构,Controller 层负责接收请求与参数校验,Service 层处理业务逻辑,Mapper 层基于 MyBatis-Plus 完成数据访问。
5.1 项目依赖配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency>5.2 饮食记录接口示例
以下代码展示新增饮食记录的核心逻辑,系统根据食物 id 查询营养数据,再按食用量折算实际摄入值。
@RestController @RequestMapping("/api/record") public class DietRecordController { @Resource private DietRecordService recordService; @PostMapping public Result<Void> addRecord(@RequestBody DietRecordDTO dto) { recordService.addRecord(dto); return Result.success(); } @GetMapping("/daily") public Result<DailyNutritionVO> getDailyNutrition( @RequestParam Long userId, @RequestParam String date) { return Result.success(recordService.getDailyNutrition(userId, date)); } }@Service public class DietRecordServiceImpl implements DietRecordService { @Resource private DietRecordMapper recordMapper; @Resource private FoodMapper foodMapper; @Override public void addRecord(DietRecordDTO dto) { Food food = foodMapper.selectById(dto.getFoodId()); if (food == null) { throw new BusinessException("食物不存在"); } DietRecord record = new DietRecord(); record.setUserId(dto.getUserId()); record.setFoodId(dto.getFoodId()); record.setMealType(dto.getMealType()); record.setAmount(dto.getAmount()); record.setRecordDate(dto.getRecordDate()); recordMapper.insert(record); } @Override public DailyNutritionVO getDailyNutrition(Long userId, String date) { List<DietRecord> records = recordMapper.selectList( new LambdaQueryWrapper<DietRecord>() .eq(DietRecord::getUserId, userId) .eq(DietRecord::getRecordDate, date)); DailyNutritionVO vo = new DailyNutritionVO(); for (DietRecord record : records) { Food food = foodMapper.selectById(record.getFoodId()); double ratio = record.getAmount() / 100.0; vo.setCalorie(vo.getCalorie() + food.getCalorie() * ratio); vo.setProtein(vo.getProtein() + food.getProtein() * ratio); vo.setFat(vo.getFat() + food.getFat() * ratio); vo.setCarbohydrate(vo.getCarbohydrate() + food.getCarbohydrate() * ratio); } return vo; } }6. 前端核心实现
前端基于 Vue3 组合式 API 开发,使用 Vite 构建,Element Plus 提供界面组件,ECharts 完成数据可视化。
6.1 项目初始化
npm create vite@latest health-diet-frontend -- --template vue cd health-diet-frontend npm install element-plus @element-plus/icons-vue axios echarts pinia6.2 饮食记录表单组件
以下为新增饮食记录的表单组件,用户选择食物、填写食用量后提交到后端接口。
<template> <el-form :model="form" label-width="80px"> <el-form-item label="食物"> <el-select v-model="form.foodId" placeholder="请选择食物"> <el-option v-for="item in foodList" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> <el-form-item label="餐次"> <el-radio-group v-model="form.mealType"> <el-radio :label="1">早餐</el-radio> <el-radio :label="2">午餐</el-radio> <el-radio :label="3">晚餐</el-radio> <el-radio :label="4">加餐</el-radio> </el-radio-group> </el-form-item> <el-form-item label="食用量"> <el-input-number v-model="form.amount" :min="1" :max="1000" /> <span> 克</span> </el-form-item> <el-form-item> <el-button type="primary" @click="submit">保存记录</el-button> </el-form-item> </el-form> </template> <script setup> import { reactive, ref, onMounted } from 'vue' import { ElMessage } from 'element-plus' import request from '@/utils/request' const form = reactive({ foodId: null, mealType: 1, amount: 100 }) const foodList = ref([]) const loadFoods = async () => { const res = await request.get('/api/food/list') foodList.value = res.data } const submit = async () => { await request.post('/api/record', form) ElMessage.success('记录成功') } onMounted(loadFoods) </script>6.3 营养趋势图表
以下代码使用 ECharts 展示近七日热量摄入趋势,数据由后端聚合接口返回。
<template> <div ref="chartRef" style="height: 360px" /> </template> <script setup> import { ref, onMounted, onBeforeUnmount } from 'vue' import * as echarts from 'echarts' import request from '@/utils/request' const chartRef = ref(null) let chart = null const loadTrend = async () => { const res = await request.get('/api/record/week-trend', { params: { userId: 1 } }) chart = echarts.init(chartRef.value) chart.setOption({ title: { text: '近七日热量摄入趋势' }, tooltip: { trigger: 'axis' }, xAxis: { type: 'category', data: res.data.dates }, yAxis: { type: 'value', name: 'kcal' }, series: [{ name: '热量摄入', type: 'line', smooth: true, data: res.data.calories }] }) } onMounted(loadTrend) onBeforeUnmount(() => { chart && chart.dispose() }) </script>7. 系统部署与运行
系统采用前后端分离部署方式,后端打包为可执行 Jar 包,前端构建为静态资源后由 Nginx 托管。
7.1 后端启动
mvn clean package -DskipTests java -jar target/health-diet-server.jar --spring.profiles.active=prod7.2 前端构建
npm run build # 构建产物位于 dist 目录,配置 Nginx 指向该目录并代理 /api 请求server { listen 80; server_name example.com; location / { root /var/www/health-diet; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }8. 总结与展望
本文基于 SpringBoot 与 Vue3 设计并实现了一套健康饮食记录与分析系统,覆盖饮食录入、营养计算、趋势分析与目标管理全流程。系统采用前后端分离架构,后端接口清晰、前端交互友好,能够满足日常饮食管理的基本需求。
后续可从以下方向持续优化:
- 接入第三方食物营养数据库,扩充食物覆盖范围。
- 增加膳食均衡评分与个性化推荐功能。
- 引入定时提醒与打卡机制,提升用户使用粘性。
- 结合运动数据,实现热量摄入与消耗的综合分析。