1.1 新增套餐需求分析

后台系统中可以管理套餐信息,通过新增套餐功能来添加一个新的套餐,在添加套餐时需要选择当前套餐所属的套餐分类和包含的菜品,并且需要上传套餐对应的图片,在移动端会按照套餐分类来展示对应的套餐。

1.2 新增套餐数据模型

新增套餐,其实就是将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal_dish表插入套餐和菜品关联数据。所以在新增套餐时,涉及到两个表:

说明 备注
setmeal 套餐表 存储套餐的基本信息
setmeal_dish 套餐菜品关系表 存储套餐关联的菜品的信息(一个套餐可以关联多个菜品)

1). 套餐表setmeal

在该表中,套餐名称name字段是不允许重复的,在建表时,已经创建了唯一索引。

2). 套餐菜品关系表setmeal_dish

在该表中,菜品的名称name,菜品的原价price 实际上都是冗余字段,因为在这张表中存储了菜品的ID(dish_id),根据该ID就可以查询出name与price的数据信息,而这里又存储了name,price。在后续的查询展示操作中,就不需要再去查询数据库获取菜品名称和原价了,这样可以简化操作。

1.3 新增套餐准备工作

在开发业务功能前,先将需要用到的类和接口基本结构创建好,无需准备Setmeal的相关实体类、Mapper接口、Service接口及实现,因为之前在做分类管理的时候,已经引入了Setmeal的相关基础代码。 接下来,我们就来完成以下的几步准备工作:

1). 实体类 SetmealDish

package com.itheima.reggie.entity;import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;/*** 套餐菜品关系*/
@Data
public class SetmealDish implements Serializable {private static final long serialVersionUID = 1L;private Long id;//套餐idprivate Long setmealId;//菜品idprivate Long dishId;//菜品名称 (冗余字段)private String name;//菜品原价private BigDecimal price;//份数private Integer copies;//排序private Integer sort;@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;@TableField(fill = FieldFill.INSERT)private Long createUser;@TableField(fill = FieldFill.INSERT_UPDATE)private Long updateUser;//是否删除private Integer isDeleted;
}

2). DTO SetmealDto

该数据传输对象DTO,主要用于封装页面在新增套餐时传递过来的json格式的数据,其中包含套餐的基本信息,还包含套餐关联的菜品集合。

package com.itheima.reggie.dto;import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import lombok.Data;
import java.util.List;@Data
public class SetmealDto extends Setmeal {private List<SetmealDish> setmealDishes;private String categoryName;
}

3). Mapper接口 SetmealDishMapper

package com.itheima.reggie.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.reggie.entity.SetmealDish;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}

4). 业务层接口 SetmealDishService

package com.itheima.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.entity.SetmealDish;public interface SetmealDishService extends IService<SetmealDish> {}

5). 业务层实现类 SetmealDishServiceImpl

package com.itheima.reggie.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.mapper.SetmealDishMapper;
import com.itheima.reggie.service.SetmealDishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;/*** Description: new java files header..** @author w* @version 1.0* @date 2022/8/19 15:35*/
@Service
@Slf4j
public class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper, SetmealDish> implements SetmealDishService {}

6). 控制层 SetmealController

套餐管理的相关业务,我们都统一在 SetmealController 中进行统一处理操作。

package com.itheima.reggie.controller;import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Description: 套餐管理* @version 1.0* @date 2022/8/19 15:37*/@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {@Autowiredprivate SetmealService setmealService;@Autowiredprivate SetmealDishService setmealDishService;@PostMappingpublic R<String> save(@RequestBody SetmealDto setmealDto){/**@Description: 新增套餐* @version v1.0* @author LiBiGo* @date 2022/8/19 16:04*/log.info("套餐信息:{}",setmealDto);setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");}}

1.4 新增套餐时前端页面和服务端的交互过程

1). 点击新建套餐按钮,访问页面(backend/page/combo/add.html),页面加载发送ajax请求,请求服务端获取套餐分类数据并展示到下拉框中(==已实现==)

获取套餐分类列表的功能我们不用开发,之前已经开发完成了,之前查询时type传递的是1,查询菜品分类; 本次查询时,传递的type为2,查询套餐分类列表。

2). 访问页面(backend/page/combo/add.html),页面加载时发送ajax请求,请求服务端获取菜品分类数据并展示到添加菜品窗口中(==已实现==)

本次查询分类列表,传递的type为1,表示需要查询的是菜品的分类。查询菜品分类的目的,是添加套餐关联的菜品时,我们需要根据菜品分类,来过滤查询菜品信息。查询菜品分类列表的代码已经实现, 具体展示效果如下:

3). 当点击添加菜品窗口左侧菜单的某一个分类, 页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中

4). 页面发送请求进行图片上传,请求服务端将图片保存到服务器(==已实现==)

5). 页面发送请求进行图片下载,将上传的图片进行回显(==已实现==)

6). 点击保存按钮,发送ajax请求,将套餐相关数据以json形式提交到服务端

经过上述的页面解析及流程分析,发送这里需要发送的请求有5个,分别是 :

A. 根据传递的参数,查询套餐分类列表(已实现)

B. 根据传递的参数,查询菜品分类列表(已实现)

C. 图片上传(已实现)

D. 图片下载展示(已实现)

E. 根据菜品分类ID,查询菜品列表

1.5 新增套餐需要开发的功能

1). 根据分类ID查询菜品列表

请求 说明
请求方式 GET
请求路径 /dish/list
请求参数 ?categoryId=1397844263642378242

2). 保存套餐信息

请求 说明
请求方式 POST
请求路径 /setmeal
请求参数 json格式数据

传递的json格式数据如下:

{"name":"营养超值工作餐","categoryId":"1399923597874081794","price":3800,"code":"","image":"9cd7a80a-da54-4f46-bf33-af3576514cec.jpg","description":"营养超值工作餐","dishList":[],"status":1,"idType":"1399923597874081794","setmealDishes":[{"copies":2,"dishId":"1423329009705463809","name":"米饭","price":200},{"copies":1,"dishId":"1423328152549109762","name":"可乐","price":500},{"copies":1,"dishId":"1397853890262118402","name":"鱼香肉丝","price":3800}]
}

1.6 根据分类查询菜品--代码开发

1.5.1 根据分类查询菜品

在当前的需求中,只需要根据页面传递的菜品分类的ID(categoryId)来查询菜品列表即可,因此直接定义一个DishController的方法,声明一个Long类型的categoryId,这样做是没问题的。

但是考虑到该方法的拓展性,我们在这里定义方法时,通过Dish这个实体来接收参数。

在DishController中定义方法list,接收Dish类型的参数:

在查询时,需要根据菜品分类categoryId进行查询,并且还要限定菜品的状态为起售状态(status为1),然后对查询的结果进行排序。

package com.itheima.reggie.controller;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.stream.Collectors;/*** Description: 菜品管理 菜品及菜品口味的相关操作,统一使用这一个controller即可。* @version 1.0* @date 2022/8/18 11:08*/@Slf4j
@RestController
@RequestMapping("/dish")
public class DishController {@Autowiredprivate DishService dishService;@Autowiredprivate DishFlavorService dishFlavorService;@Autowiredprivate CategoryService categoryService;@PostMappingpublic R<String> save(@RequestBody DishDto dishDto){/**@Description: 新增菜品* @author LiBiGo* @date 2022/8/18 11:44*/log.info(dishDto.toString());dishService.saveWithFlavor(dishDto);return R.success("新增菜品成功");}@GetMapping("/page")public R<Page> page(int page,int pageSize,String name){/**@Description: 菜品信息分页查询* @author LiBiGo** 数据库查询菜品信息时,获取到的分页查询结果 Page 的泛型为 Dish,而最终需要给前端页面返回的类型为DishDto,* 所以这个时候就要进行转换,基本属性直接通过属性拷贝的形式对Page中的属性进行复制,* 对于结果列表 records属性需要进行特殊处理的(需要封装菜品分类名称);** @date 2022/8/19 10:41*/// 构造分页构造器对象Page<Dish> pageInfo = new Page<>(page,pageSize);Page<DishDto> dishDtoPage = new Page<>();// 条件构造器LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();// 添加过滤条件queryWrapper.like(name!=null,Dish::getName,name);// 添加排序条件queryWrapper.orderByDesc(Dish::getUpdateTime);// 执行分页查询dishService.page(pageInfo,queryWrapper);// 对象的拷贝BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");List<Dish> records = pageInfo.getRecords();List<DishDto> list = records.stream().map((item) -> {DishDto dishDto = new DishDto();BeanUtils.copyProperties(item,dishDto);Long categoryId = item.getCategoryId();//分类id//根据id查询分类对象Category category = categoryService.getById(categoryId);if(category != null){String categoryName = category.getName();dishDto.setCategoryName(categoryName);}return dishDto;}).collect(Collectors.toList());dishDtoPage.setRecords(list);return R.success(dishDtoPage);}@GetMapping("/{id}")public R<DishDto> get(@PathVariable Long id){/**@Description: 根据id查询菜品信息和对应的口味信息* @author LiBiGo* @date 2022/8/19 11:43*/DishDto dishDto = dishService.getByIdWithFlavor(id);return R.success(dishDto);}@PutMapping// @PathVariable : 该注解可以用来提取url路径中传递的请求参数。public R<String> update(@RequestBody DishDto dishDto){/**@Description: 修改菜品* @author LiBiGo* @date 2022/8/19 11:58*/log.info(dishDto.toString());dishService.updateWithFlavor(dishDto);return R.success("新增菜品成功");}@GetMapping("/list")public R<List<Dish>> list(Dish dish){/**@Description: 根据条件查询对应的菜品数* @author LiBiGo* @date 2022/8/19 15:49*/// 构造查询条件LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());//添加条件,查询状态为1(起售状态)的菜品queryWrapper.eq(Dish::getStatus,1);//  添加排序条件queryWrapper.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);List<Dish> list = dishService.list(queryWrapper);return R.success(list);}}

1.5.2 根据分类查询菜品功能测试

代码编写完毕,我们重新启动服务器,进行测试,可以通过debug断点跟踪的形式查看页面传递的参数封装情况,及响应给页面的数据信息。

1.7 保存套餐功能--代码开发

1.7.1 逻辑分析

在进行套餐信息保存时,前端提交的数据,不仅包含套餐的基本信息,还包含套餐关联的菜品列表数据 setmealDishes。

解决方案:需要在Setmeal的基本属性的基础上,再扩充一个属性 setmealDishes来接收页面传递的套餐关联的菜品列表,

1). SetmealController中定义方法save,新增套餐

package com.itheima.reggie.controller;import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** Description: 套餐管理* 不仅需要保存套餐的基本信息,还需要保存套餐关联的菜品数据,所以需要再该方法中调用业务层方法,完成两块数据的保存。* @version 1.0* @date 2022/8/19 15:37*/@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {@Autowiredprivate SetmealService setmealService;@Autowiredprivate SetmealDishService setmealDishService;@PostMapping// 页面传递的数据是json格式,需要在方法形参前面加上@RequestBody注解, 完成参数封装。public R<String> save(@RequestBody SetmealDto setmealDto){/**@Description: 新增套餐* @version v1.0* @author LiBiGo* @date 2022/8/19 16:04*/log.info("套餐信息:{}",setmealDto);setmealService.saveWithDish(setmealDto);return R.success("新增套餐成功");}}

2). SetmealService中定义方法saveWithDish

package com.itheima.reggie.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.entity.Setmeal;public interface SetmealService extends IService<Setmeal> {// 新增套餐,同时需要保存套餐和菜品的关联关系public void saveWithDish(SetmealDto setmealDto);
}

3). SetmealServiceImpl实现方法saveWithDish

package com.itheima.reggie.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itheima.reggie.dto.SetmealDto;
import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import com.itheima.reggie.mapper.SetmealMapper;
import com.itheima.reggie.service.SetmealDishService;
import com.itheima.reggie.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import java.util.List;
import java.util.stream.Collectors;/*** Description: new java files header..** @author w* @version 1.0* @date 2022/8/16 10:17*/
@Service
@Slf4j
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {@Autowiredprivate SetmealDishService setmealDishService ;@Transactional@Overridepublic void saveWithDish(SetmealDto setmealDto) {/**@Description: 新增套餐,同时需要保存套餐和菜品的关联关系** A. 保存套餐基本信息* B. 获取套餐关联的菜品集合,并为集合中的每一个元素赋值套餐ID(setmealId)* C. 批量保存套餐关联的菜品集合** @author LiBiGo* @date 2022/8/19 16:10*/// 保存套餐的基本信息,操作setmeal,执行insert操作this.save(setmealDto);List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();setmealDishes.stream().map((item) -> {item.setSetmealId(setmealDto.getId());return item;}).collect(Collectors.toList());// 保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作setmealDishService.saveBatch(setmealDishes);}
}

1.7.2 功能测试

代码编写完毕,重新启动服务器,进行测试,可以通过debug断点跟踪的形式查看页面传递的参数封装情况及套餐相关数据的保存情况。

基于Springboot外卖系统17: 新增套餐模块+餐品信息回显+多数据表存储相关推荐

  1. 基于Springboot外卖系统16:菜品修改模块+菜品信息回显+ID查询口味列表+组装数据并返回

    4.1 菜品修改模块需求分析 在菜品管理列表页面点击修改按钮,跳转到修改菜品页面,在修改页面回显菜品相关信息并进行修改,最后点击确定按钮完成修改操作. 4.2 菜品修改模块前端页面(add.html) ...

  2. 基于Springboot外卖系统09:员工信息编辑+员工信息保存

    1 编辑员工信息功能 1.1 需求分析 在员工管理列表页面点击 "编辑" 按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击 "保存" 按钮完成编 ...

  3. 基于Springboot外卖系统13:实现文件上传下载模块

    1. 上传功能模块 1.1 上传概述 文件上传,也称为upload,是指将本地图片.视频.音频等文件上传到服务器上,可以供其他用户浏览或下载的过程. 文件上传时,对页面的form表单有如下要求: 表单 ...

  4. 基于Springboot外卖系统08:员工账号状态管理功能+对象转换器+扩展Spring mvc的消息转换器

    1. 员工账号状态管理 1.1 需求分析 在员工管理列表页面,可以对某个员工账号进行启用或者禁用操作.账号禁用的员工不能登录系统,启用后的员工可以正常登录.如果某个员工账号状态为正常,则按钮显示为 & ...

  5. 基于Springboot外卖系统03:pom.xml导入依赖+数据库配置文件+Boot启动类+静态资源映射

    1).在pom.xml中导入依赖 <?xml version="1.0" encoding="UTF-8"?> <project xmlns= ...

  6. 基于Springboot外卖系统05:用户非登陆状态的页面拦截器实现

    1. 完善登录功能 1.1 问题分析 用户访问接口验证,如果用户没有登录,则不让他访问除登录外的任何接口. 1.前端登录,后端创建session,返给前端 2.前端访问其他接口,失效或不存在,则返回失 ...

  7. 基于Springboot外卖系统19:用户地址+默认收货地址

    1. 用户地址簿功能 1.1 需求分析 地址簿,指的是移动端消费者用户的地址信息,用户登录成功后可以维护自己的地址信息. 同一个用户可以有多个地址信息,但是只能有一个默认地址. 对于地址簿管理,我们需 ...

  8. 基于Springboot外卖系统02:数据库搭建+Maven仓库搭建

    1 数据库环境搭建 1.1 创建数据库 可以通过以下两种方式中的任意一种, 来创建项目的数据库: 1).图形界面 注意: 本项目数据库的字符串, 选择 utf8mb4 2).命令行 1.2 数据库表导 ...

  9. java基于springboot外卖在线订餐系统(厨艺论坛)有论文

    简介 本项目主要包括了外卖订餐系统(在线订餐和外卖配送).厨艺论坛系统.管理员后台.用户中心等功能.用户注册后可以选择餐桌在线点餐支付,也可以选择外卖配送到家的方式. 演示视频 https://www ...

最新文章

  1. 2 Java NIO Channel-翻译
  2. ssh协议是tcp还是udp_DNS 支持 TCP 和 UDP 双协议,但为何偏偏只钟情 UDP?
  3. 推荐搜索炼丹笔记:MiNet阿里跨域点击率CTR预估
  4. [Leetcode][第1143题][JAVA][最长公共子序列][LCS][动态规划]
  5. 理论篇 GIT使用笔记
  6. ubuntu安装谷歌浏览器 typora+出现编码错误‘ascii‘ codec can‘t encode character ‘\u6b66‘+docker里安装tensorrt报错
  7. 解决idea修改html、js、css后,浏览器不能同步加载
  8. Ubuntu 16.04 火狐添加java插件、解决Firefox强制低版本java插件运行以及安全设置限制自签名应用程序运行
  9. VBS脚本运行库 ——文本文件的建立、追加、删除等
  10. 基于ROS使用Arduino控制水泵
  11. matlab 批量导入excel,matlab批量导入excel表格数据-Matlab如何导入excel数据
  12. 移动端车牌识别与PC端车牌识别有啥区别解析
  13. Python 编程之Tkinter的使用01
  14. 计算机DNS怎么配置,如何设置计算机dns?电脑dns设置教程
  15. 课改要实现“软着陆”
  16. GKCTF2020 逆向部分题的复现
  17. 提高转化率和获取手淘流量的技巧方法,如何提高转化率?
  18. 台积电业绩惊人,但全球芯片行业衰退影响加剧,将加码中国市场
  19. Oracle 数据库学习
  20. Pytorch学习笔记——fan_in和fan_out

热门文章

  1. “雏莺行动”:一起针对俄罗斯的窃密行动
  2. 英伟达CEO黄仁勋对话OpenAI首席科学家,谈GPT-4及未来大模型
  3. 移动端图片自适应,img固定宽高,怎么解决不同尺寸图片显示会变形的问题
  4. 两个坚持是什么_夫妻之间靠什么维持感情,一个过来男人告诉你
  5. 对接alipay支付遇到的问题
  6. Elasticsearch入门、Kibana 索引管理(elasticserch-head 插件使用, Kibanan 安装和使用)
  7. 《代码重构》读书笔记(一)
  8. 精读论文(1)------RegularFace
  9. 智能手机 3D 视觉之战:苹果不再一枝独秀,Android 全面崛起...
  10. 高效能程序员的修炼-总结篇