毕业设计实战:基于Spring Boot的厨艺交流平台全栈开发

34 阅读15分钟

一、项目背景:数字化时代的厨艺交流革新

在“互联网+生活”深度融合的当下,传统厨艺交流模式正面临信息分散、分享效率低、资源难复用等痛点:美食爱好者常因找不到系统的菜谱教程而放弃尝试,食材选购技巧、健康饮食知识也难以集中获取;厨艺达人的经验分享缺乏专属平台,优质内容易被淹没在海量信息中。

据调研,超过70%的美食爱好者曾因“菜谱步骤不清晰”“食材搭配无参考”放弃烹饪尝试,而85%的厨艺分享者希望有专业平台实现经验沉淀与互动。在此背景下,基于Spring Boot的厨艺交流平台应运而生,以“连接美食爱好者、沉淀厨艺知识、简化食材管理”为核心,构建“管理员统筹-用户分享-全民学习”的厨艺生态,让厨艺交流突破时空限制,推动生活类知识服务的数字化升级。

二、技术架构:厨艺交流平台的全栈技术选型

项目以“稳定性、易用性、扩展性”为核心设计原则,选用成熟的Java Web技术栈,确保平台在菜谱分享、食材管理、互动交流等场景下高效运行:

技术模块具体工具/技术核心作用
后端框架Spring Boot 2.x快速搭建微服务架构,简化配置,提供完整MVC解决方案,支持模块化开发
数据库MySQL 8.0存储用户信息、菜谱数据、食材详情、订单记录等业务数据,支持事务与关联查询
前端技术JSP + Bootstrap + JavaScript构建响应式界面,适配PC端多分辨率,实现表单提交、图片上传、动态交互
服务器Tomcat 9.0部署Web应用,处理HTTP请求,支持Servlet/JSP运行环境,确保高并发下的稳定性
开发工具Eclipse + Navicat集成开发环境(IDE)用于代码编写与调试,数据库管理工具用于表设计与数据维护
文件处理Apache Commons FileUpload支持菜谱图片、食材封面等文件的上传、预览与存储,处理大文件分片上传
权限控制Spring Security(扩展)实现多角色权限管理,区分管理员与普通用户的操作范围

三、项目全流程:6步完成厨艺交流平台开发

3.1 第一步:需求分析——明确平台核心价值

针对传统厨艺交流的痛点,平台聚焦“菜谱分享、食材管理、健康学习、互动交流”四大核心需求,分为功能性与非功能性两类:

3.1.1 功能性需求

  1. 两角色权限体系

    • 管理员:首页、个人中心、食材分类管理、用户管理、菜品分类管理、菜谱信息管理、食材信息管理、商品分类管理、商品信息管理、美食日志管理、健康文章管理、系统管理、订单管理;
    • 普通用户:首页、个人中心、菜谱浏览/收藏/评论、食材查询、美食日志发布、健康文章阅读、商品购买(食材周边)、订单跟踪。
  2. 核心业务功能

    • 菜谱管理:用户发布菜谱(含名称、分类、口味、烹饪时长、原材料、步骤图)、管理员审核菜谱、用户点赞/收藏/评论菜谱;
    • 食材管理:食材分类(如蔬菜、肉类、干货)、食材详情(产地、热量、食用宜忌、选购技巧)、食材关联菜谱推荐;
    • 健康学习:管理员发布健康文章(如“季节性食材搭配”“控糖饮食指南”)、用户按类型检索文章;
    • 商品与订单:食材周边商品展示(如厨房工具、预制食材)、购物车管理、订单提交与状态跟踪;
    • 互动交流:美食日志(用户记录烹饪心得)、评论互动(菜谱下提问与解答)、收藏功能(保存优质内容)。

3.1.2 非功能性需求

  • 性能要求:支持300+用户并发访问,菜谱加载时间<2秒,图片上传响应时间<1.5秒;
  • 数据安全:用户隐私信息(手机号、邮箱)加密存储,菜谱原创内容版权保护,订单数据防篡改;
  • 易用性:界面设计简洁直观,核心操作(如发布菜谱、查询食材)≤3步完成,支持“关键词搜索+分类筛选”双重检索;
  • 兼容性:支持Windows/macOS系统,适配Chrome、Edge、Firefox等主流浏览器,保证跨设备使用体验一致。

3.2 第二步:系统设计——构建整体架构

系统采用分层架构模式,各层职责清晰、低耦合,便于后续维护与功能扩展:

3.2.1 系统总体架构

  1. 表现层(Web层)

    • 负责用户交互:通过JSP动态生成管理员与普通用户的差异化界面,处理表单提交(如菜谱发布、商品下单)、页面跳转、操作反馈(如“发布成功”提示);
    • 界面适配:基于Bootstrap实现响应式布局,确保在笔记本、台式机等不同屏幕尺寸下显示正常。
  2. 业务逻辑层(Service层)

    • 核心业务处理:实现菜谱审核流程(用户提交→管理员审核→上线展示)、食材关联推荐(根据菜谱自动匹配食材)、订单状态更新(待支付→已支付→已发货);
    • 权限校验:判断当前用户角色是否有权限操作功能(如普通用户无法删除其他用户的菜谱)。
  3. 数据访问层(DAO层)

    • 数据持久化:通过MyBatis框架实现MySQL数据库的CRUD操作(如查询热门菜谱、插入用户订单);
    • 事务管理:确保关键操作(如订单提交时同步扣减商品库存)的数据一致性。

3.2.2 核心数据库设计

系统设计13张核心业务表,覆盖用户、菜谱、食材、商品、订单等全流程数据存储,确保业务连续性与数据完整性:

表名核心字段作用
yonghu(用户表)id、yonghuzhanghao(用户账号)、mima(密码)、xingming(姓名)、lianxidianhua(联系电话)、dianziyouxiang(邮箱)存储用户基本信息与联系方式
caipufenlei(菜谱分类表)id、addtime(创建时间)、caipufenlei(菜谱分类名称)存储菜谱分类(如家常菜、西餐、甜点)
caipuxinxi(菜谱信息表)id、caipinbianhao(菜品编号)、caipinmingcheng(菜品名称)、caipufenlei(菜谱分类)、kouwei(口味)、pengrenshizhang(烹饪时长)、yuancailiao(原材料)、tupian(图片)存储菜谱详情与制作步骤
shicaixinxi(食材信息表)id、shicaimingcheng(食材名称)、shicaichandi(产地)、shicaireliang(热量)、shiyongyiji(食用宜忌)、xuangoujiqiao(选购技巧)存储食材属性与使用指南
shangpinxinxi(商品信息表)id、shangpinmingcheng(商品名称)、shangpinfenlei(商品分类)、price(价格)、alllimittimes(库存)、tupian(图片)存储食材周边商品信息
dingdan(订单表)id、orderid(订单编号)、userid(用户ID)、goodid(商品ID)、buynumber(购买数量)、total(总价格)、status(订单状态)存储用户下单记录与订单进度

3.3 第三步:后端核心功能实现——Spring Boot架构

基于Spring Boot框架实现平台核心业务逻辑,重点解决“菜谱管理”“食材关联”“订单处理”等关键场景:

3.3.1 菜谱信息管理功能实现

@RestController
@RequestMapping("/api/recipe")
public class RecipeController {

    @Autowired
    private RecipeService recipeService;

    @Autowired
    private UserService userService;

    /**
     * 用户发布菜谱
     */
    @PostMapping("/publish")
    public ResponseEntity<?> publishRecipe(@RequestBody RecipePublishDTO publishDTO,
                                           @RequestHeader("token") String token) {
        try {
            // 1. 从token解析用户信息,验证身份
            String userId = JwtUtils.getUserIdFromToken(token);
            User user = userService.getById(userId);
            if (user == null) {
                return ResponseEntity.badRequest().body("用户不存在,无法发布菜谱");
            }

            // 2. 校验菜谱必填参数(名称、分类、原材料、图片不能为空)
            if (StringUtils.isEmpty(publishDTO.getCaipinmingcheng()) ||
                StringUtils.isEmpty(publishDTO.getCaipufenlei()) ||
                StringUtils.isEmpty(publishDTO.getYuancailiao()) ||
                StringUtils.isEmpty(publishDTO.getTupian())) {
                return ResponseEntity.badRequest().body("菜谱名称、分类、原材料、图片为必填项");
            }

            // 3. 封装菜谱数据,设置初始状态(待审核)
            Recipe recipe = new Recipe();
            recipe.setCaipinbianhao(generateRecipeCode()); // 生成唯一菜品编号
            recipe.setCaipinmingcheng(publishDTO.getCaipinmingcheng());
            recipe.setCaipufenlei(publishDTO.getCaipufenlei());
            recipe.setKouwei(publishDTO.getKouwei());
            recipe.setNandu(publishDTO.getNandu());
            recipe.setPengrenshizhang(publishDTO.getPengrenshizhang());
            recipe.setTupian(publishDTO.getTupian());
            recipe.setYuancailiao(publishDTO.getYuancailiao());
            recipe.setCaipinjieshao(publishDTO.getCaipinjieshao());
            recipe.setUserId(userId);
            recipe.setStatus("待审核"); // 初始状态:待管理员审核
            recipe.setAddtime(new Date());

            Recipe savedRecipe = recipeService.saveRecipe(recipe);
            return ResponseEntity.ok("菜谱发布成功,等待管理员审核");
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("菜谱发布失败:" + e.getMessage());
        }
    }

    /**
     * 管理员审核菜谱
     */
    @PostMapping("/audit")
    public ResponseEntity<?> auditRecipe(@RequestBody RecipeAuditDTO auditDTO,
                                         @RequestHeader("token") String token) {
        try {
            // 1. 验证管理员权限
            if (!JwtUtils.checkRole(token, "admin")) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body("无审核权限,仅管理员可操作");
            }

            // 2. 查找菜谱并更新审核状态
            Recipe recipe = recipeService.getById(auditDTO.getRecipeId());
            if (recipe == null) {
                return ResponseEntity.badRequest().body("菜谱不存在");
            }

            recipe.setStatus(auditDTO.getAuditResult()); // "通过"或"驳回"
            recipe.setAuditTime(new Date());
            recipeService.updateRecipe(recipe);

            return ResponseEntity.ok("菜谱审核完成,状态已更新为:" + auditDTO.getAuditResult());
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("审核操作失败:" + e.getMessage());
        }
    }

    /**
     * 生成唯一菜品编号(格式:REC+年月日+6位随机数)
     */
    private String generateRecipeCode() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String dateStr = sdf.format(new Date());
        String randomStr = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        return "REC" + dateStr + randomStr;
    }

    /**
     * 用户查询菜谱列表(支持按分类、口味筛选)
     */
    @GetMapping("/list")
    public ResponseEntity<?> getRecipeList(
            @RequestParam(required = false) String caipufenlei,
            @RequestParam(required = false) String kouwei,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        try {
            RecipeQuery query = new RecipeQuery();
            query.setCaipufenlei(caipufenlei);
            query.setKouwei(kouwei);
            query.setPageNum(page);
            query.setPageSize(size);

            PageInfo<RecipeVO> recipePage = recipeService.getRecipePage(query);
            return ResponseEntity.ok(recipePage);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("获取菜谱列表失败:" + e.getMessage());
        }
    }
}

3.3.2 食材信息管理功能实现

@Service
@Transactional
public class IngredientService {

    @Autowired
    private IngredientMapper ingredientMapper;

    @Autowired
    private IngredientCategoryMapper categoryMapper;

    /**
     * 添加食材信息
     */
    public Ingredient addIngredient(IngredientCreateDTO createDTO) {
        // 1. 验证食材分类是否存在
        IngredientCategory category = categoryMapper.selectByCategoryName(createDTO.getShicaifenlei());
        if (category == null) {
            throw new RuntimeException("食材分类不存在,请先创建分类");
        }

        // 2. 封装食材数据
        Ingredient ingredient = new Ingredient();
        ingredient.setShicaimingcheng(createDTO.getShicaimingcheng());
        ingredient.setShicaifenlei(createDTO.getShicaifenlei());
        ingredient.setShicaichandi(createDTO.getShicaichandi());
        ingredient.setShicaididian(createDTO.getShicaididian());
        ingredient.setShicaireliang(createDTO.getShicaireliang());
        ingredient.setFabushijian(new Date());
        ingredient.setShicaifengmian(createDTO.getShicaifengmian());
        ingredient.setShiyongyiji(createDTO.getShiyongyiji());
        ingredient.setXuangoujiqiao(createDTO.getXuangoujiqiao());
        ingredient.setAddtime(new Date());

        ingredientMapper.insert(ingredient);
        return ingredient;
    }

    /**
     * 根据菜谱ID推荐关联食材(基于菜谱原材料匹配)
     */
    public List<IngredientVO> recommendIngredientsByRecipeId(Long recipeId) {
        // 1. 获取菜谱的原材料信息(如“土豆、牛肉、洋葱”)
        Recipe recipe = recipeMapper.selectById(recipeId);
        if (recipe == null) {
            throw new RuntimeException("菜谱不存在");
        }
        String rawMaterials = recipe.getYuancailiao();
        if (StringUtils.isEmpty(rawMaterials)) {
            return Collections.emptyList();
        }

        // 2. 拆分原材料关键词,匹配食材表
        String[] materialArr = rawMaterials.split("、");
        List<String> materialList = Arrays.asList(materialArr);

        // 3. 查询匹配的食材
        return ingredientMapper.selectByMaterialList(materialList);
    }

    /**
     * 用户查询食材详情(含食用宜忌、选购技巧)
     */
    public IngredientVO getIngredientDetail(Long ingredientId) {
        Ingredient ingredient = ingredientMapper.selectById(ingredientId);
        if (ingredient == null) {
            throw new RuntimeException("食材不存在");
        }

        // 转换为VO返回(隐藏敏感字段,只返回用户需要的信息)
        IngredientVO vo = new IngredientVO();
        BeanUtils.copyProperties(ingredient, vo);
        return vo;
    }
}

3.3.3 订单管理功能实现

@RestController
@RequestMapping("/api/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private ProductService productService;

    /**
     * 用户提交订单(购买食材周边商品)
     */
    @PostMapping("/submit")
    public ResponseEntity<?> submitOrder(@RequestBody OrderCreateDTO createDTO,
                                         @RequestHeader("token") String token) {
        try {
            // 1. 验证用户身份
            String userId = JwtUtils.getUserIdFromToken(token);
            User user = userService.getById(userId);
            if (user == null) {
                return ResponseEntity.badRequest().body("用户不存在");
            }

            // 2. 验证商品库存
            Product product = productService.getById(createDTO.getGoodId());
            if (product == null) {
                return ResponseEntity.badRequest().body("商品不存在");
            }
            if (product.getAlllimittimes() < createDTO.getBuynumber()) {
                return ResponseEntity.badRequest().body("商品库存不足,当前库存:" + product.getAlllimittimes());
            }

            // 3. 计算订单总金额(单价 × 购买数量)
            BigDecimal totalAmount = product.getPrice()
                    .multiply(new BigDecimal(createDTO.getBuynumber()));

            // 4. 提交订单
            Order order = orderService.createOrder(createDTO, userId, totalAmount);
            return ResponseEntity.ok(order);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("订单提交失败:" + e.getMessage());
        }
    }

    /**
     * 用户查询个人订单列表
     */
    @GetMapping("/my-orders")
    public ResponseEntity<?> getMyOrders(@RequestHeader("token") String token,
                                         @RequestParam(defaultValue = "1") int page,
                                         @RequestParam(defaultValue = "10") int size) {
        try {
            String userId = JwtUtils.getUserIdFromToken(token);
            PageInfo<OrderVO> orderPage = orderService.getUserOrders(userId, page, size);
            return ResponseEntity.ok(orderPage);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("获取订单列表失败:" + e.getMessage());
        }
    }

    /**
     * 管理员更新订单状态(如“已发货”“已完成”)
     */
    @PostMapping("/update-status")
    public ResponseEntity<?> updateOrderStatus(@RequestBody OrderStatusDTO statusDTO,
                                               @RequestHeader("token") String token) {
        try {
            // 验证管理员权限
            if (!JwtUtils.checkRole(token, "admin")) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).body("无权限更新订单状态");
            }

            orderService.updateOrderStatus(statusDTO.getOrderId(), statusDTO.getStatus());
            return ResponseEntity.ok("订单状态更新成功");
        } catch (Exception e) {
            return ResponseEntity.internalServerError().body("更新订单状态失败:" + e.getMessage());
        }
    }
}

3.4 第四步:前端界面实现——两角色适配界面

基于JSP + Bootstrap构建差异化界面,遵循“生活美学+操作简洁”的设计原则,确保管理员高效管理、普通用户轻松使用:

3.4.1 普通用户界面

  • 首页:轮播展示热门菜谱、食材分类入口(如“当季食材”“厨房必备”)、健康文章推荐;
  • 菜谱中心:网格布局展示菜谱缩略图,点击进入详情页(含原材料、步骤图、用户评论),支持“收藏”“点赞”操作;
  • 食材查询:按分类(蔬菜/肉类/干货)或关键词(如“低热量”)检索食材,查看食用宜忌与选购技巧;
  • 美食日志:发布烹饪心得(支持图文混排)、查看他人日志并评论互动;
  • 商品商城:浏览食材周边商品(如厨房刀具、有机调料),加入购物车并下单;
  • 个人中心:编辑个人信息、查看我的收藏/订单/日志、修改密码。

3.4.2 管理员界面

  • 数据概览:平台用户数、菜谱总数、订单量等核心数据统计;
  • 内容管理:菜谱审核(查看详情→通过/驳回)、健康文章发布、食材信息维护;
  • 用户管理:用户列表(查询/禁用)、用户反馈处理;
  • 商品管理:添加商品(名称/价格/库存/图片)、商品上下架、库存更新;
  • 订单管理:查看所有订单、更新订单状态(待支付→已发货→已完成)、订单导出;
  • 系统设置:分类管理(菜谱分类、食材分类)、轮播图配置、系统公告发布。 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

3.5 第五步:系统测试——确保平台稳定可靠

通过“功能测试+兼容性测试+性能测试”三维度测试策略,验证平台在实际使用场景中的可用性与稳定性:

3.5.1 功能测试

设计覆盖核心业务流程的测试用例,确保各功能模块正常运行:

测试场景测试用例预期结果实际结果是否通过
菜谱发布用户提交含名称、原材料、步骤图的菜谱菜谱保存成功,状态为“待审核”菜谱保存成功,状态为“待审核”
食材推荐查看“土豆炖牛肉”菜谱,点击“关联食材”显示“土豆、牛肉、洋葱”等食材显示“土豆、牛肉、洋葱”等食材
商品下单用户购买“厨房剪刀”(库存10),购买数量2订单提交成功,库存更新为8订单提交成功,库存更新为8
权限控制普通用户尝试删除其他用户的菜谱提示“无权限操作”提示“无权限操作”

3.5.2 兼容性与性能测试

  • 兼容性测试:在Chrome 120、Edge 119、Firefox 118浏览器中测试,所有界面正常显示,图片上传、订单提交等功能无异常;
  • 性能测试
    • 并发测试:模拟200用户同时浏览菜谱,页面加载时间<1.8秒,无卡顿;
    • 数据存储测试:上传100张菜谱图片(单张3MB),存储成功且预览加载正常;
    • 稳定性测试:连续72小时运行,菜谱发布、订单提交等核心操作无失败案例。

3.6 第六步:问题排查与优化——提升平台体验

开发过程中针对关键问题制定优化方案,确保平台易用性与稳定性:

  1. 问题:菜谱图片上传慢、预览加载卡顿
    解决方案:前端使用图片压缩插件(localResizeIMG)将图片压缩至1MB以内,后端采用分块上传,生成缩略图用于列表预览。

  2. 问题:食材推荐匹配准确率低
    解决方案:优化关键词匹配算法,支持“同义词匹配”(如“马铃薯”匹配“土豆”),增加食材标签体系(如“低卡”“易储存”)。

  3. 问题:订单并发提交导致库存超卖
    解决方案:数据库添加乐观锁(version字段),订单提交时校验库存版本,确保库存扣减唯一性;使用Redis缓存热门商品库存,减少数据库查询压力。

  4. 问题:移动端适配体验差
    解决方案:优化响应式布局,针对手机屏幕调整按钮大小与字体间距;新增“菜谱步骤折叠”功能,避免移动端滚动过长。

四、毕业设计复盘:经验总结与实践建议

4.1 开发过程中的技术挑战

  1. 内容关联性:菜谱与食材的关联推荐需要精准的算法支持,避免推荐无关食材;
  2. 数据一致性:订单提交、库存扣减等操作需确保事务一致性,防止数据异常;
  3. 用户体验:美食类平台对图片展示要求高,需平衡“图片质量”与“加载速度”;
  4. 权限精细度:管理员与普通用户的操作边界需清晰,避免越权访问。

4.2 给后续开发者的建议

  1. 功能扩展方向

    • AI菜谱生成:基于用户输入的食材,自动生成菜谱步骤与烹饪建议;
    • 视频教程:支持菜谱视频上传与播放,提升教程直观性;
    • 社区互动:新增“厨艺挑战赛”“美食打卡”功能,增强用户粘性;
    • 个性化推荐:基于用户浏览历史,推荐相似菜谱与食材。
  2. 技术优化建议

    • 引入Redis缓存:缓存热门菜谱、食材列表,减少数据库查询压力;
    • 微服务拆分:将“菜谱服务”“订单服务”“用户服务”拆分为独立微服务,提升系统扩展性;
    • 前端框架升级:使用Vue.js替代JSP,实现前后端分离,提升页面交互体验;
    • 云存储集成:将菜谱图片、视频存储至阿里云OSS,降低服务器存储压力。

五、项目资源与发展展望

5.1 项目核心资源

本项目提供完整的开发与部署资料,便于后续学习与二次开发:

  • 后端源码:Spring Boot项目完整源码(含Controller/Service/DAO层实现);
  • 前端资源:JSP页面文件、Bootstrap样式、JavaScript交互脚本、美食主题图片素材;
  • 数据库脚本:MySQL建表语句、初始化数据(测试账号/示例菜谱);
  • 部署文档:环境配置指南(JDK/Tomcat/MySQL安装)、系统部署步骤、运维注意事项;
  • 接口文档:基于Swagger的RESTful API文档,含接口参数与返回值说明。

5.2 平台发展展望

  1. 垂直领域深化:针对“减脂餐”“儿童辅食”“地域特色菜”等细分场景,开发专属模块,提供个性化内容;
  2. 商业化探索:引入食材电商功能,对接线下商超,实现“菜谱浏览→食材购买→教程学习”闭环;
  3. 智能化升级:集成AI图像识别技术,支持“拍照识食材”“菜品评分”,提升平台科技感;
  4. 多端适配:开发微信小程序与移动端APP,支持用户随时随地浏览菜谱、发布日志。

如果本文对您的Spring Boot学习、生活类管理系统毕业设计有帮助,欢迎点赞 + 收藏 + 关注,后续会分享更多垂直领域管理系统的实战案例!