当前位置: 首页 > news >正文

6--苍穹外卖-SpringBoot项目中菜品管理 详解(二)

目录

菜品分页查询

需求分析和设计

代码开发

设计DTO类

设计VO类

Controller层

Service层接口

Service层实现类

Mapper层

功能测试

删除菜品

需求设计和分析

代码开发

Controller层

Service层接口

Service层实现类

Mapper层

功能测试

修改菜品

需求分析和设计

代码开发

根据id查询菜品实现

Controller层

Service层接口

Service层实现类

Mapper层

修改菜品实现

Controller层

Service层接口

Service层实现类

Mapper层

功能测试


  
1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客

2--苍穹外卖-SpringBoot项目中员工管理 详解(一)-CSDN博客

3--苍穹外卖-SpringBoot项目中员工管理 详解(二)-CSDN博客

4--苍穹外码-SpringBoot项目中分类管理 详解-CSDN博客

5--苍穹外卖-SpringBoot项目中菜品管理 详解(一)-CSDN博客

6--苍穹外卖-SpringBoot项目中菜品管理 详解(二)-CSDN博客

7--苍穹外卖-SpringBoot项目中套餐管理 详解(一)-CSDN博客

8--苍穹外卖-SpringBoot项目中套餐管理 详解(二)-CSDN博客

9--苍穹外卖-SpringBoot项目中Redis的介绍及其使用实例 详解-CSDN博客

菜品分页查询

需求分析和设计

业务规则:

  • 根据页码展示菜品信息

  • 每页展示10条数据

  • 分页查询时可以根据需要输入菜品名称、菜品分类、菜品状态进行查询

代码开发

设计DTO类

根据菜品分页查询接口定义设计对应的DTO:

在sky-pojo模块中

package com.sky.dto;import lombok.Data;import java.io.Serializable;@Data
public class DishPageQueryDTO implements Serializable {private int page;private int pageSize;private String name;//分类idprivate Integer categoryId;//状态 0表示禁用 1表示启用private Integer status;}
设计VO类

根据菜品分页查询接口定义设计对应的VO:(在返回的数据中categoryName属于另外一个文件中,需要使用VO转换属性为json,方便前端展示)

在sky-pojo模块中

package com.sky.vo;import com.sky.entity.DishFlavor;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DishVO implements Serializable {private Long id;//菜品名称private String name;//菜品分类idprivate Long categoryId;//菜品价格private BigDecimal price;//图片private String image;//描述信息private String description;//0 停售 1 起售private Integer status;//更新时间private LocalDateTime updateTime;//分类名称private String categoryName;//菜品关联的口味private List<DishFlavor> flavors = new ArrayList<>();//private Integer copies;
}
Controller层

根据接口定义创建DishController的page分页查询方法:

//菜品分页查询@GetMapping("/page")@ApiOperation("菜品分页查询")public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO){log.info("菜品分页查询:{}",dishPageQueryDTO);PageResult pageResult=dishService.pageQuery(dishPageQueryDTO);return Result.success(pageResult);}
Service层接口

在 DishService 中扩展分页查询方法:

 //菜品分页查询PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);
Service层实现类

在 DishServiceImpl 中实现分页查询方法:

 //菜品分页查询@Overridepublic PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());Page<DishVO> page= dishMapper.pageQuery(dishPageQueryDTO);return new PageResult(page.getTotal(),page.getResult());}
Mapper层

在 DishMapper 接口中声明 pageQuery 方法:

 //菜品分页查询Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);

在 DishMapper.xml 中编写SQL:

 <select id="pageQuery" resultType="com.sky.vo.DishVO">select d.* ,c.name as categoryName from dish d left outer join category c on d.category_id=c.id<where><if test="name!=null">and d.name like concat('%',#{name},'%')</if><if test="categoryId!=null">and d.category_id=#{categoryId}</if><if test="status!=null">and d.status=#{status}</if></where>order by d.create_time desc</select>

功能测试

删除菜品

需求设计和分析

业务规则:

  • 可以一次删除一个菜品,也可以批量删除菜品

  • 起售中的菜品不能删除

  • 被套餐关联的菜品不能删除

  • 删除菜品后,关联的口味数据也需要删除掉

代码开发

Controller层

根据删除菜品的接口定义在DishController中创建方法:

//菜品批量删除@DeleteMapping@ApiOperation("菜品批量删除")public Result<String> delete(@RequestParam List<Long> ids){//@RequestParam注解使用mvc框架,可以获取到参数1,2,3中的变量值log.info("菜品批量删除,{}",ids);dishService.deleteBatch(ids);return Result.success();}
Service层接口

在DishService接口中声明deleteBatch方法:

  //菜品批量删除void deleteBatch(List<Long> ids);
Service层实现类

在DishServiceImpl中实现deleteBatch方法:

  //菜品批量删除@Transactional//事务public void deleteBatch(List<Long> ids) {//判断当前菜品是否能够删除---是否存在起售中的菜品for (Long id : ids) {//根据主键查询菜品Dish dish=dishMapper.getById(id);//查询是否起售if (Objects.equals(dish.getStatus(), StatusConstant.ENABLE)){//当前菜品处于起售中,不能删除throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);}}//判断当前菜品是否能够删除---是否被套餐关联了List<Long> setmealIds=setmealDishMapper.getSetmealIdsByDishIds(ids);if (setmealIds!=null&& !setmealIds.isEmpty()){//当前菜品被套餐关联了,不能删除throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);}//删除菜品表中的菜品数据for (Long id : ids) {dishMapper.deleteById(id);//删除菜品关联的口味数据dishFlavorMapper.deleteByDishId(id);}
Mapper层

在DishMapper中声明getById方法,并配置SQL:

 //根据主键查询菜品@Select("select *from dish where id=#{id}")Dish getById(Long id);

创建SetmealDishMapper,声明getSetmealIdsByDishIds方法,并在xml文件中编写SQL:

package com.sky.mapper;import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface SetmealDishMapper {//根据菜品id查询对应的套餐idList<Long> getSetmealIdsByDishIds(List<Long> dishIds);}

SetmealDishMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper"><select id="getSetmealIdsByDishIds" resultType="java.lang.Long">select setmeal_id from setmeal_dish where dish_id in<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">#{dishId}</foreach></select>
</mapper>

在DishMapper.java中声明deleteById方法并配置SQL:

    //根据主键删除菜品数据@Delete("delete from dish where id=#{id}")void deleteById(Long id);

在DishFlavorMapper中声明deleteByDishId方法并配置SQL:

 //根据菜品id删除对应的口味数据@Delete("delete from dish_flavor where dish_id=#{dishId}")void deleteByDishId(Long dishId);

 性能优化

在DishServiceImpl中,删除菜品是一条一条传送执行的,大大降低了执行效率,原代码如下:

//删除菜品表中的菜品数据for (Long id : ids) {dishMapper.deleteById(id);//删除菜品关联的口味数据dishFlavorMapper.deleteByDishId(id);}

为了提高性能,进行修改,使用动态sql执行删除操作

 //根据菜品id集合批量删除菜品数据//sql:delete from dish where id in(?,?,?)dishMapper.deleteByIds(ids);//根据菜品id集合批量删除关联的口味数据//sql:delete from dish_flavor where dish_id in(?,?,?)dishMapper.deleteByDishIds(ids);

在DishMapper中

 //根据菜品id集合批量删除菜品void deleteByIds(List<Long> ids);//根据菜品id集合批量删除关联的口味数据void deleteByDishIds(List<Long> dishId);

在DishMapper.xml中

 <delete id="deleteByIds">delete from dish where id in<foreach collection="ids" open="(" separator="," close=")" item="id">#{id}</foreach></delete><delete id="deleteByDishIds">delete from dish_flavor where dish_id in<foreach collection="dishIds" open="(" close=")" separator="," item="dishId">#{dishId}</foreach></delete>

功能测试

进行前后端联调,删除成功

修改菜品

需求分析和设计

接口:

  • 根据id查询菜品

  • 根据类型查询分类(已实现)

  • 文件上传(已实现)

  • 修改菜品

代码开发

根据id查询菜品实现

Controller层

根据id查询菜品的接口定义在DishController中创建方法:

 //根据id查询菜品@GetMapping("/{id}")@ApiOperation("根据id查询菜品")public  Result<DishVO> getById(@PathVariable Long id){log.info("根据id查询菜品:{}",id);DishVO dishVO=dishService.getByIdWithFlavor(id);return  Result.success(dishVO);}
Service层接口

在DishService接口中声明getByIdWithFlavor方法:

 //根据id查询菜品和对应的口味数据DishVO getByIdWithFlavor(Long id);
Service层实现类

在DishServiceImpl中实现getByIdWithFlavor方法:

//根据id查询菜品和对应的口味数据@Overridepublic DishVO getByIdWithFlavor(Long id) {//根据id查询菜品数据Dish dish=dishMapper.getById(id);//根据菜品id查询口味数据List<DishFlavor> dishFlavors=dishFlavorMapper.getByDishId(id);//将查询到的数据封装到VODishVO dishVO = new DishVO();BeanUtils.copyProperties(dish,dishVO);dishVO.setFlavors(dishFlavors);return dishVO;}
Mapper层

在DishFlavorMapper中声明getByDishId方法,并配置SQL:

//根据id查询对应的口味数据@Select("select *from dish_flavor where dish_id=#{dishId}")List<DishFlavor> getByDishId(Long dishId);

修改菜品实现

Controller层

根据修改菜品的接口定义在DishController中创建方法:

 //修改菜品@PutMapping@ApiOperation("修改菜品")public Result<String> update(@RequestBody DishDTO dishDTO){log.info("修改菜品:{}",dishDTO);dishService.updateWithFlavor(dishDTO);return Result.success();}
Service层接口

在DishService接口中声明updateWithFlavor方法:

 //根据id修改菜品基本信息和对应的口味数据void updateWithFlavor(DishDTO dishDTO);
Service层实现类

在DishServiceImpl中实现updateWithFlavor方法:

//根据id修改菜品基本信息和对应的口味信息@Overridepublic void updateWithFlavor(DishDTO dishDTO) {Dish dish = new Dish();BeanUtils.copyProperties(dishDTO,dish);//修改菜品表基本信息dishMapper.update(dish);//删除原有的口味数据dishFlavorMapper.deleteByDishId(dishDTO.getId());//重新插入口味数据List<DishFlavor> flavors = dishDTO.getFlavors();if (flavors!=null&& !flavors.isEmpty()){flavors.forEach(dishFlavor -> {dishFlavor.setDishId(dishDTO.getId());});//向口味表插入n条数据dishFlavorMapper.insertBatch(flavors);}}
Mapper层

在DishMapper中,声明update方法:

 //根据id动态修改菜品数据@AutoFill(value = OperationType.UPDATE)void update(Dish dish);

并在DishMapper.xml文件中编写SQL:

 <update id="update">update dish<set><if test="name!=null">name=#{name},</if><if test="categoryId!=null">category_id=#{categoryId},</if><if test="price!=null">price=#{price},</if><if test="image!=null">image=#{image},</if><if test="description!=null">description=#{description},</if><if test="status!=null">status=#{status},</if><if test="updateTime!=null">update_time=#{updateTime},</if><if test="updateUser!=null">update_user=#{updateUser},</if></set>where id=#{id}</update>

功能测试

相关文章:

6--苍穹外卖-SpringBoot项目中菜品管理 详解(二)

目录 菜品分页查询 需求分析和设计 代码开发 设计DTO类 设计VO类 Controller层 Service层接口 Service层实现类 Mapper层 功能测试 删除菜品 需求设计和分析 代码开发 Controller层 Service层接口 Service层实现类 Mapper层 功能测试 修改菜品 需求分析和设…...

游戏怎么录制?王者荣耀游戏录制指南:iOS与电脑端全面教程

在王者荣耀的战场上&#xff0c;每一个五杀、每一次极限逃生都可能成为你游戏生涯中的高光时刻。但这些瞬间往往转瞬即逝&#xff0c;如何将它们永久保存&#xff0c;成为你游戏历程中不可磨灭的印记呢&#xff1f;本文将为你揭晓答案。无论你是手持iPhone的iOS用户&#xff0c…...

Vue.js组件开发指南

Vue.js组件开发指南 Vue.js 是一个渐进式的 JavaScript 框架&#xff0c;用于构建用户界面。它的核心是基于组件的开发模式。通过将页面分解为多个独立的、可复用的组件&#xff0c;开发者能够更轻松地构建复杂的应用。本文将深入探讨 Vue.js 组件开发的基础知识&#xff0c;并…...

【流计算】流计算概论

前言 作者在之前写过一个大数据的专栏&#xff0c;包含GFS、BigTable、MapReduce、HDFS、Hadoop、LSM树、HBase、Spark&#xff0c;专栏地址&#xff1a; https://blog.csdn.net/joker_zjn/category_12631789.html?fromshareblogcolumn&sharetypeblogcolumn&sharerI…...

20230819盘锦锦州葫芦岛自驾

2023年08月19日&#xff0c;上午带娃和老人驾车前往朝阳&#xff0c;逛凤凰山&#xff0c;中午吃了免费的素面味道不错。下午开车去鸟化石公园单独买儿童票43元。晚上驾车到盘锦&#xff0c;住红海滩民宿95元。 2023年08月20日&#xff0c;逛盘锦红海滩一天&#xff0c;有稻田画…...

Unity 与虚幻引擎对比:两大游戏开发引擎的优劣分析

在游戏开发领域&#xff0c;Unity 和虚幻引擎&#xff08;Unreal Engine&#xff09;是两款最为知名且广泛使用的引擎。它们各有特点&#xff0c;适合不同类型的开发者和项目。在这篇博客中&#xff0c;我们将深入探讨这两大引擎的核心功能、适用场景、优缺点&#xff0c;以及如…...

UDS_4_传输存储的数据功能单元

目录 一. DTC 二. 0x14服务 三. 0x19服务 3.1 0x19服务 3.2 0x01子功能 3.3 0x02子功能 3.4 0x04子功能 3.5 0x06子功能 3.6 0x0A子功能 一. DTC 》DTC-Diagnostic Trouble Code J1939-73 DTCFormat DTC SPN FMI CM OC 8-1位 8-1位 8-6位 5-1位 8位 7-1位 字节1 字节…...

第二百五十八节 JPA教程 - JPA查询选择两个实体示例

JPA教程 - JPA查询选择两个实体示例 以下JPQL从两个实体中选择。 List l em.createQuery("SELECT d, m FROM Department d, Professor m WHERE d m.department").getResultList();例子 以下代码来自Professor.java。 package cn.w3cschool.common;import java.…...

数据库三级模式结构

三级模式结构 1. 外模式&#xff08;External Schema&#xff09;——“用户看到的楼层”2. 概念模式&#xff08;Conceptual Schema&#xff09;——“图书馆的核心”3. 内模式&#xff08;Internal Schema&#xff09;——“图书馆的地下室”举例1. 概念模式的例子2. 外模式的…...

【小程序websocket最佳实践,有心跳和断线重连】

小程序websocket最佳实践&#xff0c;有心跳和断线重连 封装了WebSocketHandler类&#xff0c;用于管理websocket链接&#xff0c;保证链接的稳定和可靠&#xff0c;该类主要适用于小程序&#xff0c;但其设计思想和方法也适用于其他平台。 export default class WebSocketHa…...

自然资源部最新Nature正刊!!!

2024年8月21日&#xff0c;国际顶级期刊《Nature》发表了自然资源部第二海洋研究所李家彪院士为通讯作者&#xff0c;张涛为第一作者的论文“超慢速扩张加克洋中脊的高变化岩浆增生”。这一成果颠覆了国际海洋学术界半个多世纪以来一直认为的超慢速扩张洋中脊岩浆供给极度贫瘠的…...

git分支-创建、合并、删除

Git会将每次提交串成一条时间线&#xff0c;这条时间线就是一个分支。在最初&#xff0c;只有一个master分支 在目录下创建项目 对目录进行输入 项目被修改 创建dev分支 合并分支 删除dev分支...

Python:Spoonfed - (2-10) 激励选择脚本(搬砖)

https://www.patreon.com/posts/python-spoonfed-31572219 2019年11月15日 利用上一课的选择函数&#xff0c;我们现在可以拼凑出一些脚本&#xff08;有一些事情我们还没有解释&#xff0c;但应该很容易理解&#xff09;。以下代码将允许您选择当前所选对象的父对象、顶级对…...

VS Code Python 文件导入提示 xxx Module 不存在解决方式

VS Code Python 文件导入提示 xxx Module 不存在解决方式 引言正文如何打开 setting.json 文件引言 之前在 https://blog.csdn.net/u011699626/article/details/142612579?spm=1001.2014.3001.5501 一文中我们介绍了如何配置 VS code 中 Jupyter Notebook 的文件导入环境,这…...

Android中的Activity与Fragment:深入解析与应用场景

在Android应用开发中&#xff0c;Activity和Fragment是两个核心概念&#xff0c;它们各自扮演着不同的角色&#xff0c;共同构成了用户界面的基础。理解并熟练掌握这两个组件的使用&#xff0c;对于开发高效、灵活且用户友好的Android应用至关重要。本文将深入解析Activity与Fr…...

Flux【lora模型】【真人模型】:极致逼真,小红书真实风格|旅游拍照|景点打卡

大家好我是安琪&#xff01;&#xff01;&#xff01; 今天和大家推荐一款基于Flux训练的真人写实的lora模型&#xff1a;Flux_小红书真实风格丨日常照片丨极致逼真。一看这个模型的命名&#xff0c;就可以猜测出以小红书日常真实拍摄的照片为数据集训练而来&#xff0c;该模型…...

python基础语法--顺序结构

Python中的顺序结构主要包括流程控制语句&#xff0c;如 if、while 和 for 语句。这些语句允许你在程序中定义不同的执行路径&#xff0c;从而根据条件或循环次数来改变代码的执行流程。下面详细介绍这些语句的使用方法和示例。 if 语句 if 语句用于根据某个条件来决定是否执…...

软件游戏运行缺少vcruntime140.dll怎么办?总结四种有效简单方法

1. 文件基本信息 1.1 定义与作用 vcruntime140.dll是Microsoft Visual C 2015 Redistributable Package的一部分&#xff0c;它包含了C运行时库&#xff0c;用于支持使用Visual C开发的Windows应用程序。这个动态链接库&#xff08;DLL&#xff09;文件提供了程序执行时所需的…...

(undone) 阅读 MapReduce 论文笔记

参考&#xff1a;https://pdos.csail.mit.edu/6.824/papers/mapreduce.pdf 摘要&#xff1a;简单介绍了 MapReduce 是在大型分布式系统上工作的 Introduction 的内容总结&#xff1a; 1.介绍背景&#xff1a;为什么我们需要分布式系统&#xff1f;MapReduce 的意义是哪些 2.简…...

sql注入工具升级:自动化时间盲注、布尔盲注

项目地址&#xff1a;https://github.com/iamnotamaster/sql-injecter 给我之前写的sql注入脚本进行了一些升级&#xff0c;此文章就是对升级内容的分析&#xff0c;升级内容如下&#xff1a; 使用占位符foo来填充payload里需要经常修改的部分 自动判断循环 支持爆破和二分查…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

家政维修平台实战20:权限设计

目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系&#xff0c;主要是分成几个表&#xff0c;用户表我们是记录用户的基础信息&#xff0c;包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题&#xff0c;不同的角色&#xf…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?

Redis 的发布订阅&#xff08;Pub/Sub&#xff09;模式与专业的 MQ&#xff08;Message Queue&#xff09;如 Kafka、RabbitMQ 进行比较&#xff0c;核心的权衡点在于&#xff1a;简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...