作为一名长期从事Java全栈开发的工程师,最近完成了一个基于SpringBoot+Vue的膳食营养健康管理平台。这个项目特别适合作为计算机相关专业的毕业设计或课程设计,因为它涵盖了现代Web开发的完整技术栈,包括前后端分离架构、RESTful API设计、数据库建模等核心内容。
这个平台的核心价值在于将传统的膳食记录和营养分析数字化。用户可以通过简单的操作记录每日饮食,系统会自动计算摄入的营养成分,并给出专业的健康评估和建议。对于开发者而言,项目展示了如何将SpringBoot的后端能力与Vue的前端优势相结合,构建一个功能完整的企业级应用。
平台采用经典的前后端分离架构,这种设计模式在现代Web开发中已经成为主流选择。后端使用SpringBoot框架构建RESTful API服务,前端则采用Vue.js框架实现用户界面。两者通过HTTP协议进行通信,实现了业务逻辑与表现层的完全解耦。
选择这种架构主要基于以下考虑:
后端技术栈:
前端技术栈:
提示:在实际开发中,建议锁定这些依赖的具体版本号,避免因版本升级导致的兼容性问题。
数据库设计遵循第三范式,确保数据的一致性和完整性。以下是三个核心表的设计思路:
用户表(user_profile):
sql复制CREATE TABLE `user_profile` (
`user_id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password_hash` varchar(100) NOT NULL,
`email` varchar(100) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`birth_date` date DEFAULT NULL,
`height` float DEFAULT NULL,
`weight` float DEFAULT NULL,
`register_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`user_id`),
UNIQUE KEY `idx_username` (`username`),
UNIQUE KEY `idx_email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
膳食记录表(diet_log):
sql复制CREATE TABLE `diet_log` (
`log_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`food_name` varchar(100) NOT NULL,
`calories` float NOT NULL,
`protein` float NOT NULL,
`carb` float NOT NULL,
`fat` float NOT NULL,
`log_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`log_id`),
KEY `idx_user_id` (`user_id`),
CONSTRAINT `fk_user` FOREIGN KEY (`user_id`) REFERENCES `user_profile` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
健康报告表(health_report):
sql复制CREATE TABLE `health_report` (
`report_id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`bmi` float NOT NULL,
`suggestion` text NOT NULL,
`generate_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`report_id`),
KEY `idx_user_id` (`user_id`),
CONSTRAINT `fk_user_report` FOREIGN KEY (`user_id`) REFERENCES `user_profile` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
在实际开发中,我们针对性能做了以下优化:
标准的Maven项目结构如下:
code复制src/main/java
├── com.nutri.app
│ ├── config # 配置类
│ ├── controller # 控制器层
│ ├── dto # 数据传输对象
│ ├── entity # 实体类
│ ├── exception # 异常处理
│ ├── mapper # MyBatis映射接口
│ ├── service # 业务逻辑层
│ └── util # 工具类
src/main/resources
├── application.yml # 应用配置
├── static # 静态资源
└── templates # 模板文件
以用户注册为例,展示典型的Controller-Service-Mapper三层架构:
UserController.java
java复制@RestController
@RequestMapping("/api/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/register")
public Result register(@Valid @RequestBody UserRegisterDTO dto) {
userService.register(dto);
return Result.success();
}
}
UserServiceImpl.java
java复制@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public void register(UserRegisterDTO dto) {
// 检查用户名是否已存在
if (userMapper.existsByUsername(dto.getUsername())) {
throw new BusinessException("用户名已存在");
}
// 密码加密
String encodedPassword = passwordEncoder.encode(dto.getPassword());
// 构建用户实体
User user = new User();
user.setUsername(dto.getUsername());
user.setPasswordHash(encodedPassword);
user.setEmail(dto.getEmail());
// 保存到数据库
userMapper.insert(user);
}
}
BMI计算是健康评估的基础:
java复制public class HealthCalculator {
public static float calculateBMI(float height, float weight) {
if (height <= 0 || weight <= 0) {
throw new IllegalArgumentException("身高和体重必须大于0");
}
float heightInMeter = height / 100;
return weight / (heightInMeter * heightInMeter);
}
public static String getBMICategory(float bmi) {
if (bmi < 18.5) return "偏瘦";
else if (bmi < 24) return "正常";
else if (bmi < 28) return "超重";
else return "肥胖";
}
}
使用Vue CLI创建的标准项目结构:
code复制src/
├── api/ # API请求封装
├── assets/ # 静态资源
├── components/ # 公共组件
├── router/ # 路由配置
├── store/ # Vuex状态管理
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue # 根组件
└── main.js # 入口文件
膳食记录页面的核心代码示例:
DietLog.vue
vue复制<template>
<div class="diet-log">
<el-form :model="form" label-width="120px">
<el-form-item label="食物名称">
<el-input v-model="form.foodName" />
</el-form-item>
<el-form-item label="热量(kcal)">
<el-input-number v-model="form.calories" :min="0" />
</el-form-item>
<!-- 其他营养成分字段 -->
<el-button type="primary" @click="submit">提交记录</el-button>
</el-form>
<el-table :data="logs" style="width: 100%">
<el-table-column prop="foodName" label="食物名称" />
<el-table-column prop="calories" label="热量(kcal)" />
<!-- 其他列 -->
</el-table>
</div>
</template>
<script>
import { addDietLog, getDietLogs } from '@/api/diet'
export default {
data() {
return {
form: {
foodName: '',
calories: 0,
protein: 0,
carb: 0,
fat: 0
},
logs: []
}
},
methods: {
async submit() {
await addDietLog(this.form)
this.$message.success('记录添加成功')
this.loadLogs()
},
async loadLogs() {
const res = await getDietLogs()
this.logs = res.data
}
},
created() {
this.loadLogs()
}
}
</script>
使用ECharts展示营养摄入趋势图:
vue复制<template>
<div ref="chart" style="width: 100%; height: 400px;"></div>
</template>
<script>
import * as echarts from 'echarts'
export default {
props: ['nutrientData'],
mounted() {
this.initChart()
},
methods: {
initChart() {
const chart = echarts.init(this.$refs.chart)
const option = {
title: { text: '营养摄入趋势' },
tooltip: { trigger: 'axis' },
legend: { data: ['热量', '蛋白质', '碳水', '脂肪'] },
xAxis: { type: 'category', data: this.nutrientData.dates },
yAxis: { type: 'value' },
series: [
{ name: '热量', type: 'line', data: this.nutrientData.calories },
{ name: '蛋白质', type: 'line', data: this.nutrientData.protein },
{ name: '碳水', type: 'line', data: this.nutrientData.carb },
{ name: '脂肪', type: 'line', data: this.nutrientData.fat }
]
}
chart.setOption(option)
}
}
}
</script>
后端开发环境:
前端开发环境:
后端部署步骤:
mvn clean packagetarget/nutri-app-0.0.1-SNAPSHOT.jarjava -jar nutri-app-0.0.1-SNAPSHOT.jar前端部署步骤:
npm installnpm run build注意:生产环境务必配置HTTPS,确保数据传输安全。可以使用Let's Encrypt获取免费SSL证书。
问题1:跨域请求被浏览器拦截
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*");
}
}
javascript复制module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true
}
}
}
}
问题2:MyBatis查询结果映射失败
yaml复制mybatis:
configuration:
map-underscore-to-camel-case: true
问题1:前端路由刷新404
nginx复制location / {
try_files $uri $uri/ /index.html;
}
问题2:数据库连接池耗尽
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
idle-timeout: 30000
max-lifetime: 1800000
这个基础平台可以进一步扩展以下功能:
在实际开发中,我发现最值得投入的是营养分析算法的优化。通过收集更多用户数据,可以建立更精准的营养评估模型。另外,前端性能优化也是提升用户体验的关键,特别是对于包含大量数据可视化的页面。