1. 项目背景与核心需求
中华美食文化源远流长,但传统菜谱信息分散在各个平台,缺乏系统化的整理和互动功能。作为一名Java开发者,我决定用SpringBoot构建一个集菜谱展示、教学、交流于一体的Web平台。这个系统需要解决三个核心痛点:
- 信息整合难题:将八大菜系、地方特色等分散的食谱集中管理
- 学习体验优化:提供步骤化教学和食材搭配建议
- 社区互动缺失:建立用户间的收藏、评论、分享机制
系统采用B/S架构,前端使用Thymeleaf模板引擎,后端基于SpringBoot+MyBatis技术栈,数据库选用MySQL 5.7。这种技术组合既保证了开发效率,又能满足毕业设计对技术深度的要求。
提示:项目开发前建议先完成《需求规格说明书》,明确功能边界。我在初期因需求模糊导致多次返工,这是新手常见误区。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计
2.1 技术选型解析
后端技术栈:
- SpringBoot 2.7.3:简化配置,内置Tomcat
- MyBatis-Plus 3.5.1:增强CRUD操作
- Shiro 1.8.0:权限控制
- Lombok:简化实体类编写
前端技术栈:
- Bootstrap 5:响应式布局
- jQuery 3.6:DOM操作
- Layer:弹层组件
开发环境:
- JDK 1.8
- IntelliJ IDEA 2022
- Navicat Premium 15
选择这些技术主要基于:
- SpringBoot的自动配置特性适合快速开发
- MyBatis-Plus的代码生成器可节省50%的DAO层代码量
- Shiro比Spring Security更轻量,学习曲线平缓
2.2 数据库设计要点
数据库设计遵循第三范式,核心表包括:
sql复制CREATE TABLE `recipe` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL COMMENT '菜品名称',
`cuisine_id` int DEFAULT NULL COMMENT '菜系ID',
`cooking_time` int DEFAULT NULL COMMENT '烹饪时长(分钟)',
`difficulty` tinyint DEFAULT '1' COMMENT '难度(1-5)',
`ingredients` text COMMENT '食材JSON',
`steps` text COMMENT '步骤JSON',
`cover_img` varchar(255) DEFAULT NULL,
`creator_id` int DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
特别注意:
- 食材和步骤使用JSON格式存储,便于前端解析
- 建立复合索引
idx_cuisine_difficulty(cuisine_id, difficulty)提升查询效率 - 图片存储采用相对路径,实际文件存放在Nginx静态资源目录
3. 核心功能实现
3.1 菜谱发布模块
采用富文本编辑器WangEditor实现图文混排:
java复制@PostMapping("/publish")
public Result publishRecipe(@Valid RecipeDTO dto) {
// 转换食材格式
String ingredients = JSON.toJSONString(dto.getIngredientList());
Recipe recipe = new Recipe();
BeanUtils.copyProperties(dto, recipe);
recipe.setIngredients(ingredients);
recipe.setCreatorId(getCurrentUserId());
if(recipeService.save(recipe)){
return Result.success(recipe.getId());
}
return Result.error("发布失败");
}
避坑经验:
- 图片上传需限制为2MB以内,格式仅允许jpg/png
- 使用Hutool的ImgUtil压缩图片,避免加载卡顿
- 敏感词过滤采用DFA算法,建立美食领域专有词库
3.2 智能搜索功能
结合Elasticsearch实现多条件检索:
java复制public Page<RecipeVO> search(SearchQuery query) {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
// 关键词搜索
if(StringUtils.isNotBlank(query.getKeyword())){
builder.withQuery(QueryBuilders.multiMatchQuery(query.getKeyword(),
"name","ingredients","tips"));
}
// 菜系过滤
if(query.getCuisineId() != null){
builder.withFilter(QueryBuilders.termQuery("cuisine_id", query.getCuisineId()));
}
// 分页处理
builder.withPageable(PageRequest.of(query.getPage()-1, query.getSize()));
return recipeEsRepository.search(builder.build());
}
实测搜索响应时间从MySQL的1200ms降至200ms左右。建议给Elasticsearch分配至少2GB内存,并定期执行_optimize操作。
4. 特色功能开发
4.1 烹饪教学系统
采用时间轴方式展示步骤:
html复制<div class="steps-container">
<div th:each="step,iter : ${recipe.steps}" class="step-item">
<div class="step-index">[[${iter.count}]]</div>
<img th:src="${step.imgUrl}"
class="step-img"
@click="showFullscreen(step.imgUrl)">
<div class="step-desc">[[${step.content}]]</div>
<div class="step-timer" th:if="${step.duration > 0}">
<i class="icon-clock"></i>
[[${step.duration}]]分钟
</div>
</div>
</div>
交互优化点:
- 添加步骤图片放大查看功能
- 关键步骤设置计时器提醒
- 实现横屏模式适配手机端
4.2 食材搭配分析
基于Apriori算法实现关联推荐:
python复制# Python数据分析服务(Java调用)
def find_ingredient_patterns():
df = pd.read_sql("SELECT ingredients FROM recipe", conn)
transactions = df['ingredients'].apply(lambda x: json.loads(x))
te = TransactionEncoder()
te_ary = te.fit(transactions).transform(transactions)
df = pd.DataFrame(te_ary, columns=te.columns_)
freq_items = apriori(df, min_support=0.1, use_colnames=True)
rules = association_rules(freq_items, metric="lift", min_threshold=1.2)
return rules.sort_values('lift', ascending=False)
常见搭配组合:
- 鱼香肉丝:猪肉+木耳+笋丝(支持度0.32)
- 宫保鸡丁:鸡胸肉+花生+干辣椒(支持度0.28)
5. 部署与性能优化
5.1 生产环境部署
采用Docker Compose编排服务:
yaml复制version: '3'
services:
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: 123456
volumes:
- ./mysql/data:/var/lib/mysql
elasticsearch:
image: elasticsearch:7.17.3
environment:
discovery.type: single-node
ulimits:
memlock:
soft: -1
hard: -1
app:
build: .
ports:
- "8080:8080"
depends_on:
- mysql
- elasticsearch
部署注意事项:
- MySQL需配置字符集为utf8mb4以支持emoji
- ES的JVM堆内存建议设置为系统内存的50%
- 使用Nginx做静态资源缓存和负载均衡
5.2 性能调优实战
通过Jmeter压测发现接口响应较慢,采取以下优化措施:
-
缓存策略:
java复制@Cacheable(value = "recipes", key = "#id") public RecipeVO getById(Integer id) { return baseMapper.selectVoById(id); }使用Redis缓存热点菜谱,QPS从150提升到2100
-
SQL优化:
sql复制EXPLAIN SELECT * FROM recipe WHERE cuisine_id = 3 ORDER BY create_time DESC LIMIT 10;添加组合索引
(cuisine_id, create_time)后查询时间从230ms降至28ms -
异步处理:
java复制@Async public void updateViewCount(Integer recipeId) { recipeMapper.incrementViewCount(recipeId); }浏览量统计改为异步更新,主接口响应时间减少65%
6. 开发经验总结
-
版本控制:使用Git规范分支管理,
feature/开发分支完成后需通过Pull Request合并到dev分支。曾因直接push到main分支导致代码冲突。 -
异常处理:统一异常处理器记录日志时,要注意脱敏用户隐私信息。我在开发初期误将用户手机号记录到日志文件。
-
接口文档:使用Swagger UI生成API文档,但要注意
@ApiIgnore隐藏管理接口。建议配合Postman制作接口测试集合。 -
数据备份:设置MySQL每日自动备份到OSS,有次服务器故障靠备份节省了三天工作量。
这个项目让我深刻体会到,一个完整的Web系统开发需要兼顾功能实现、性能优化和运维部署多个维度。特别是在高并发场景下,缓存和数据库设计的好坏直接影响用户体验。下一步我计划加入AI菜品识别功能,通过拍照自动匹配相似菜谱。
