外卖点餐APP-04(后台--菜品管理)

(一)新增

controller层思路:

  1. 调用service处理
  2. 响应处理结果
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){dishService.saveWithFlavors(dishDto);return R.success("新增成功!");
}

service层

public interface DishService extends IService<Dish> {void saveWithFlavors(DishDto dishDto);
}

serviceImpl层思路:

注意:由于新增菜品操作了两张表  进行了2个写操作,要保证插入菜品基本信息和口味信息同时成功 新增菜品才成功 所以需要添加事务管理,在方法上打上@Transactional注解以及在启动类上开启事务注解驱动管理即可

  1. 检查菜品名称不能重复
  2. 保存菜品基本信息到菜品口味表dish,可以直接传dishDto对象 因为dishDto继承了Dish  插入时只会根据Dish类中有的属性设置插入字段的值 多余的字段会自动忽略
  3. 获取菜品id  MyBatisPlus中当完成了新增操作之后,会自动的将生成的id赋值到对象的主键属性上
  4. 保存菜品口味信息到菜品口味表dish_flavor
  5. 获取菜品口味信息列表
  6. 为当前的菜品口味设置关联的菜品id dish_id字段
@Transactional
@Override
public void saveWithFlavors(DishDto dishDto) {LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();wrapper.eq(Dish::getName,dishDto.getName());Integer count = dishDao.selectCount(wrapper);if (count>0){throw new CustomException(0,"菜品名称'"+dishDto.getName()+"'已经存在");}dishDao.insert(dishDto);Long dishDtoId = dishDto.getId();List<DishFlavor> flavors = dishDto.getFlavors();flavors.stream().forEach(flavor->{flavor.setDishId(dishDtoId);dishFlavorDao.insert(flavor);});
}

(二)分页查询

controller层

@GetMapping("/page")
public R<Page<DishDto>> page(@RequestParam(defaultValue="1") Integer page, @RequestParam(defaultValue="10") Integer pageSize, String name){//1.调用service处理Page<DishDto> dishPage = dishService.findPage(page,pageSize,name);//2.响应处理结果return R.success(dishPage);
}

service层

public interface DishService extends IService<Dish> {Page<DishDto> findPage(Integer page, Integer pageSize, String name);
}

serviceImpl层

注意事项:

问题1:分页查询时 菜品图片没有显示
       原因:没有将测试数据中 菜品对应图片放入 D:\reggie\目录下
       解决:将资源中提供的图片资源放入D:\reggie\目录下
问题2:分页查询时  菜品所属的分类名称没有展示
       原因:前端页面进行菜品所属分类展示时 需要的是菜品分类名称categoryName 而我们查询菜品表返回的数据只有菜品所属分类id 没有分类名称
       解决

  1. 分页查询返回菜品列表数据的同时  在每一条菜品数据中应该包含菜品的所属分类名称categoryName
  2. 将每一个菜品dish对象中的数据 封装到dishDto对象中,并且设置dishDto对象的categoryName属性即可实现前端的正常展示
  3. 响应的数据  Page<Dish>>   ==》     Page<DishDto>>
  4. 原来响应的给前端的数据是        R<Page<Dish>> ----->    Page<Dish>:封装分页相关的数据 records:当前页数据List<Dish>     total:总条数
  5. 现在我们要响应给前端的数据是     R<Page<DishDto>> ----> Page<DishDto>:封装分页相关的数据  records:当前页数据 List<DishDto>  total:总条数

实际实现步骤:

  1. 从dishPage对象中获取当前页数据列表 dishList  List<Dish>
  2. 遍历dishList集合 将集合中的每一个dish对象中的数据赋值到DishDto对象中,并且为DishDto对象的categoryName属性赋值
  3. 在遍历dishList集合时,将每一个新创建出来的dishDto对象 存入到dishDtoList集合中 【这样就得到当前页要显示的数据集合了】
  4. 将当前页数据集合dishDtoList和总条数封装到dishDtoPage对象中返回即可
@Override
public Page<DishDto> findPage(Integer page, Integer pageSize, String name) {//0.配置分页查询拦截器  【已经配置好了】//1.封装分页参数page和pageSize到Page对象中Page<Dish> dishPage = new Page<>(page, pageSize);//2.设置分页查询条件 根据菜品名称name进行模糊查询LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();wrapper.like(name!=null&&name.length()>0,Dish::getName,name);//3.调用selectPage方法 传入Page对象和wrapper对象完成分页查询dishDao.selectPage(dishPage,wrapper);//完善代码:响应Page<DishDto>//a:创建Page<DishDto> dishDtoPage对象Page<DishDto> dishDtoPage = new Page<>();//b.将dishPage中的当前页数据集合List和总条数设置到dishDtoPage对象//当前页数据列表ListList<Dish> dishList = dishPage.getRecords();//b1:将dishList中的每一个元素dish对象转为DishDto 存入到List<DishDto> dishDtoList中List<DishDto> dishDtoList = new ArrayList<>();for (Dish dish : dishList) {//创建DishDto对象DishDto dishDto = new DishDto();//将dish对象中的菜品信息赋值到dishDto对象中,要注意源对象的属性和目标对象的属性要一致BeanUtils.copyProperties(dish,dishDto);//查询当前菜品所属的分类名称Category category = categoryDao.selectById(dish.getCategoryId());dishDto.setCategoryName(category.getName());//将dishDto对象放入到DishDtoList集合中dishDtoList.add(dishDto);}//将当前页要显示的数据 设置到dishDtoPage对象的records属性上dishDtoPage.setRecords(dishDtoList);//b2:将总条数设置到dishDtoPage对象的total属性上dishDtoPage.setTotal(dishPage.getTotal());//4.返回Page对象【Page对象中包含当前页数据集合List和总条数】return dishDtoPage;
}

(三)ID条件查询

controller层

@GetMapping("/{id}")
public R<DishDto> getById(@PathVariable Long id){//1.调用service处理DishDto dishDto = dishService.getByIdWithFlavors(id);//2.响应处理结果return R.success(dishDto);
}

service层

public interface DishService extends IService<Dish> {DishDto getByIdWithFlavors(Long id);
}

serviceImpl层思路:

  1. 根据菜品id查询菜品的基本信息数据
  2. 根据菜品id查询菜品的口味信息数据
  3. 将菜品的基本信息及其口味信息封装到DishDto对象中返回
  4. 使用Spring提供的BeanUtils工具类 可以将一个源对象的属性数据赋值到一个目标对象属性上 要求属性名称前后一致
  5. 返回结果
//根据id查询菜品信息
@Override
public DishDto getByIdWithFlavors(Long id) {Dish dish = dishDao.selectById(id);LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();wrapper.eq(DishFlavor::getId,id);List<DishFlavor> flavors = dishFlavorDao.selectList(wrapper);DishDto dishDto = new DishDto();BeanUtils.copyProperties(dish,dishDto);dishDto.setFlavors(flavors);return dishDto;
}

(四)修改

controller层

@PutMapping
public R<String> update(@RequestBody DishDto dishDto){//1.调用service处理dishService.updateWithFlavors(dishDto);//2.响应处理结果return R.success("修改成功!");
}

service层

public interface DishService extends IService<Dish> {void updateWithFlavors(DishDto dishDto);
}

serviceImpl层思路:

  1. 判断菜品修改后要保存的菜品名称不能和其他的菜品名称相同
  2. 修改菜品dish表中的菜品基本信息
  3. 修改菜品口味dish_flavor表中的菜品口味信息
  4. 获取当前菜品id
  5. 删除当前菜品对应的所有口味信息   根据菜品口味对应的菜品id进行删除
  6. 将当前菜品修改后的口味信息保存到dish_flavor表中
  7. 获取当前菜品修改后的口味信息列表
  8. 循环遍历 要设置口味的id置为null,口味关联的dish_id要设置为当前菜品id,口味的id置为null,口味关联当前菜品dish_id,保存到dish_flavor表中。
@Transactional
@Override
public void updateWithFlavors(DishDto dishDto) {LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();wrapper.eq(Dish::getName,dishDto.getName());wrapper.ne(Dish::getId,dishDto.getId());Integer count = dishDao.selectCount(wrapper);if (count>0){throw new CustomException(0,"菜品名称'"+dishDto.getName()+"'已存在!");}dishDao.updateById(dishDto);Long dishId = dishDto.getId();LambdaQueryWrapper<DishFlavor> flavorLambdaQueryWrapper = new LambdaQueryWrapper<>();flavorLambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);dishFlavorDao.delete(flavorLambdaQueryWrapper);List<DishFlavor> flavors = dishDto.getFlavors();flavors.stream().forEach(flavor->{flavor.setId(null);flavor.setDishId(dishId);dishFlavorDao.insert(flavor);});
}

(五)删除

controller层

//删除菜品
@DeleteMapping("/{ids}")
public R<String> deleteByIds(@PathVariable Long[] ids){//1.调用service处理dishService.deleteByIds(ids);//2.响应处理结果return R.success("删除成功!");
}

service层

public interface DishService extends IService<Dish> {void deleteByIds(Long[] ids);
}

serviceImpl层思路:

  1. 判断ids中是否为null  提示:没有选中要删除的套餐
  2. 判断要删除的套餐是否处于停售状态  如果处于起售状态:则不能删除 抛出异常提示,根据要删除的套餐id  设置查询条件status=1 进行统计 如果个数大于1,说明存在启售状态的套餐,不能删除
//删除
@Transactional
@Override
public void deleteByIds(Long[] ids) {if (ids==null||ids.length==0){throw new CustomException(0,"没有选中要删除的套餐");}LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();List<Long> idsList = Arrays.asList(ids);wrapper.in(Dish::getId,idsList);List<Dish> dishList = this.list(wrapper);dishList.stream().forEach(dish -> {if (dish.getStatus()==1){throw new CustomException(0,"当前菜品'"+dish.getName()+"'处于启售状态,无法删除!");}Long dishId = dish.getId();LambdaQueryWrapper<DishFlavor> dishFlavorWrapper = new LambdaQueryWrapper<>();dishFlavorWrapper.eq(DishFlavor::getDishId,dishId);dishFlavorDao.delete(dishFlavorWrapper);this.removeById(dish.getId());});}

(六)启用 && 禁用 (批量)

controller层

//启用禁用
@PostMapping("/status/{status}")
public R<String> updateEmp(@PathVariable Integer status,@RequestParam List<Long> ids){dishService.updateDishStatus(status, ids);return R.success("修改成功!");
}

service层

public interface DishService extends IService<Dish> {void updateDishStatus(Integer status,List<Long> ids);
}

serviceImpl层

//批量启售禁售
@Override
public void updateDishStatus(Integer status, List<Long> ids) {LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();wrapper.in(ids!=null,Dish::getId,ids);List<Dish> lists = this.list(wrapper);lists.stream().forEach(list->{if (list!=null){list.setStatus(status);this.updateById(list);}});
}

(七)根据菜品分类id和菜品名称查询菜品列表数据

本次偷懒,全在在controller层实现

  1. 调用service处理,得到菜品列表数据
  2. 创建wrapper对象
  3. 设置查询条件,菜品所属分类id、菜品名称、菜品状态status
  4. 添加查询条件  当status不为null时,设置查询启售的菜品列表数据
  5. 调用list方法查询
  6. 循环遍历List<Dish>集合,将菜品的基本信息封装到DishDto对象中
  7. 还需要根据菜品的分类id和菜品id查询出所属分类名称和菜品的口味信息封装到DishDto对象中
  8. 将DishDto存入到List集合中 返回
  9. 响应数据
//根据菜品分类id和菜品名称查询菜品列表数据
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish){LambdaQueryWrapper<Dish> wrapper = new LambdaQueryWrapper<>();wrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId()); //当分类id不为null 根据分类id进行查询wrapper.like(dish.getName()!=null,Dish::getName,dish.getName());    //当菜品名称name不为null,根据菜品名称进行模糊查询wrapper.eq(dish.getStatus()!=null,Dish::getStatus,dish.getStatus());  //查询启售的菜品List<Dish> list = dishService.list(wrapper);List<DishDto> dishDtoList = list.stream().map((item)->{DishDto dishDto = new DishDto();BeanUtils.copyProperties(item,dishDto);Category category = categoryService.getById(item.getCategoryId());dishDto.setCategoryName(category==null?"未知":category.getName());LambdaQueryWrapper<DishFlavor> wrapper1 = new LambdaQueryWrapper<>();wrapper1.eq(DishFlavor::getDishId,item.getId());List<DishFlavor> flavors = dishFlavorService.list(wrapper1);dishDto.setFlavors(flavors);return dishDto;}).collect(Collectors.toList());return R.success(dishDtoList);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34122.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

瑞吉外卖:后台系统登录和退出功能

文章目录 需求分析代码开发创建实体类导入返回结果类Rcontroller、service与mapperlogin.html防止非法访问 需求分析 点击登录按钮后&#xff0c;浏览器以POST方式向employee/login提交username和password&#xff0c;服务器经过处理后向浏览器返回某种格式的数据&#xff0c;…

服装销售数据分析

目录&#xff1a; 一、项目背景介绍 二、数据源 三、分析流程 四、分析框架 五、知识点总结 一、项目背景介绍&#xff1a; 某服装经销商经营多个女装品牌&#xff0c;每个品牌设有线下店铺。该公司老板及销售总监需在每日营业结束后查看当日销售数据。以往主要由业务员手动整…

创建报价单或销售凭证,提示无定价确定过程能被确定,消息号V1212

创建报价单&#xff0c;提示无定价确定过程能被确定&#xff0c;消息号V1212。 解决方案&#xff1a; spro 》销售和分销——》基本功能——》定价——》定价控制——》定价并分配定价过程 1&#xff09;将凭证定价程序分配给订单类型 2&#xff09;设置定价程序确定&#xff0…

ChatGPT工作提效之layedit上传多附件的解决方案(layedit赋值、layui.js底层修改、追加模式多附件上传)

ChatGPT工作提效系列文章目录 ChatGPT工作提效之初探路径独孤九剑遇强则强ChatGPT工作提效之在程序开发中的巧劲和指令(创建MySQL语句、PHP语句、Javascript用法、python的交互)ChatGPT工作提效之生成开发需求和报价单并转为Excel格式ChatGPT工作提效之小鹅通二次开发批量API对…

Zia和ChatGPT如何协同工作?

有没有集成ChatGPT的CRM系统推荐&#xff1f;Zoho CRM已经正式与ChatGPT集成。下面我们将从使用场景、使用价值和使用范围等方面切入讲述CRMAI的应用和作用。 Zia和ChatGPT如何协同工作&#xff1f; Zia和ChatGPT是不同的人工智能模型&#xff0c;在CRM中呈现出共生的关系。 …

AIGC持续火爆大模型争相推出,庞大市场造就算力供应模式演变

本图由AI生成 文/王吉伟 近期的AIGC领域仍旧火爆异常。 但火的不只是AIGC应用&#xff0c;还有巨头之间的AI竞赛&#xff0c;以及接连不断上新的AI大模型&#xff08;LLM&#xff0c;Large Language Model&#xff09;。 面对ChatGPT带来的技术冲击&#xff0c;为了研发谷歌多…

ChatGPT实现命名实体识别(NER, named entity recognization)和词性归类

语义分析词格分类 命名实体识别(NER, named entity recognization)和词性归类是 NLP 技术中的关键一环。过去 NLP 领域有不少流行的开源项目专注在这个领域&#xff0c;如 Spacy、NLTK 等等。我们来试试 ChatGPT 在这方面的表现情况如何。我们从"四渡赤水"的百度百科…

突发!两所知名大学,曝合并!校方紧急回应:校长将亲自说明!

点击上方“3D视觉工坊”&#xff0c;选择“星标” 干货第一时间送达 来源丨联合新闻网 编辑丨3D视觉工坊 点击进入—>3D视觉工坊学习交流群 我国台湾又有“国立”大学传出合并的消息&#xff0c;台湾中山大学与台湾高雄大学传将重启合并协商&#xff0c;有网友曝光中山大学发…

从 Uber 数据泄露事件我们可以学到什么?

Uber 数据泄露始于一名黑客从暗网市场购买属于一名 Uber 员工的被盗凭证。最初尝试使用这些凭据连接到 Uber 的网络失败&#xff0c;因为该帐户受 MFA 保护。为了克服这一安全障碍&#xff0c;黑客通过 What’s App 联系了 Uber 员工&#xff0c;并假装是 Uber 的安全人员&…

点击率预估

点击率预估是广告技术的核心算法之一&#xff0c;它是很多广告算法工程师喜爱的战场。一直想介绍一下点击率预估&#xff0c;但是涉及公式和模型理论太多&#xff0c;怕说不清楚&#xff0c;读者也不明白。所以&#xff0c;这段时间花了一些时间整理点击率预估的知识&#xff0…

老鸟教你如何精确评估开发时间

一个程序员能否精确评估开发时间&#xff0c;是一件非常重要的事情。如果你掌握了这项技能&#xff0c;你在别人的眼里就会是这样&#xff1a; 靠谱经验十足对需求很了解延期风险小合格的软件工程师正规军&#xff0c;不是野路子 评估开发时间的重要性 首先&#xff0c;在一…

从FM推演各深度CTR预估模型(附代码)

作者&#xff1a; 龙心尘 && 寒小阳 时间&#xff1a;2018年7月 出处&#xff1a;https://blog.csdn.net/longxinchen_ml/article/details/81031736 https://blog.csdn.net/han_xiaoyang/article/details/81031961 声明&#xff1a;版权所有&#xff0c;转载请联系作者…

[项目管理] 如何评估工作量

1.1. 工作量估算的定义 工作量估算 即对开发软件产品所需的人力和时间的估算——人力成本是一个项目的主要成本。 我们可以根据预估的工作量决定具体由几个人、哪几个人参与该项目。 工作量通常以 人/天、人/月、人/年 的形式来衡量。 1.2. 为什么要进行工作量估算 做好工…

机器学习实战 | 综合项目-电商销量预估

作者&#xff1a;韩信子ShowMeAI 教程地址&#xff1a;https://www.showmeai.tech/tutorials/41 本文地址&#xff1a;https://www.showmeai.tech/article-detail/206 声明&#xff1a;版权所有&#xff0c;转载请联系平台与作者并注明出处 收藏ShowMeAI查看更多精彩内容 1.案例…

Python:实现进度条和时间预估

一、前言 在python当中可以用进度条来显示工作的进度&#xff0c;比如for循环的进度或者一些模型训练的进度。 在这里可以使用progressbar包以及tqdm包来实现。 使用pip install progressbar 安装progressbar包。 使用pip install tqdm安装tqdm包。 二、代码 1. progress…

如何科学预估开发时间

0. 我是前言 一个开发人员能否精确评估开发时间&#xff0c;是一件非常重要的事情。如果你掌握了这项技能&#xff0c;你在别人的眼里就会是这样&#xff1a; 1. 评估开发时间的重要性 首先&#xff0c;在一个项目中&#xff0c;所有的环节都是承上启下的&#xff0c;不管你是…

编译原理之代码生成

前面提到了经过了词法分析->语法分析->语义分析->中间代码优化&#xff0c;最后的阶段便是在目标机器上运行的目标代码的生成了。目标代码生成阶段的任务是&#xff1a;将此前的中间代码转换成特定机器上的机器语言或汇编语言&#xff0c;这种转换程序便被称为代码生成…

前端案例-跟随鼠标移动的天使

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域新星创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

前端代码在线编辑器:codepen、codesandbox

文章目录 单文件在线编辑器项目级在线编辑器 推荐两个前端代码在线编辑器 单文件在线编辑器&#xff1a;https://codepen.io/pen/ 项目级在线编辑器&#xff1a;https://codesandbox.io/ 单文件在线编辑器 codepen 相信使用 element-ui组件库的小伙伴应该知道 codepen在线编…

vue前端生成二维码并提供二维码下载

在一个管理后台的开发过程中使用到了需要前端自行生成分享二维码&#xff0c;并提供二维码下载功能&#xff0c;网上的解决方案很多&#xff0c;最终自己做完的思路和代码整理记录方便后续学习使用&#xff01; vue版本为2.x 具体实现步骤&#xff1a; 下载安装依赖&#xff0…