1 菜品展示
1.1 需求分析
用户登录成功后跳转到系统首页,在首页需要根据分类来展示菜品和套餐。如果菜品设置了口味信息,需要展示 按钮,否则显示按钮。
1.2 前端页面分析
在开发代码之前,需要梳理一下前端页面和服务端的交互过程:
1). 页面(front/index.html)发送ajax请求,获取分类数据(菜品分类和套餐分类)
该功能已经实现了。通过请求响应的数据可以看到数据是可以正确获取到的。
左侧的分类菜单,和右侧的菜品信息都可以看到,后续只需要将购物车列表的数据改成调用服务端接口查询即可。
2). 页面发送ajax请求,获取第一个分类下的菜品或者套餐
A. 根据分类ID查询套餐列表:
B. 根据分类ID查询菜品列表:
异步请求,查询分类对应的菜品列表已经实现了,但是查询的只是菜品的基本信息,不包含菜品的口味信息。所以在前端界面中看不到选择菜品分类的信息。
经过上述的分析,服务端我们主要提供两个方法, 分别用来:
A. 根据分类ID查询菜品列表(包含菜品口味列表), 具体请求信息如下:
请求 | 说明 |
请求方式 | GET |
请求路径 | /dish/list |
请求参数 | ?categoryId=1397844263642378242&status=1 |
该功能在服务端已经实现,需要修改此方法,在原有方法的基础上增加查询菜品的口味信息。
B. 根据分类ID查询套餐列表, 具体请求信息如下:
请求 | 说明 |
请求方式 | GET |
请求路径 | /setmeal/list |
请求参数 | ?categoryId=1397844263642378242&status=1 |
该功能在服务端并未实现。
2 代码开发
2.1 查询菜品方法修改
由于之前实现的根据分类查询菜品列表,仅仅查询了菜品的基本信息,未查询菜品口味信息,而移动端用户在点餐时,是需要选择口味信息的,所以需要对之前的代码实现进行完善。
需要修改DishController的list方法,原来此方法的返回值类型为:R<List<Dish>>。为了满足移动端对数据的要求(菜品基本信息和菜品对应的口味信息),现在需要将方法的返回值类型改为:R<List<DishDto>> ,因为在DishDto中封装了菜品对应的口味信息:
代码逻辑:
A. 根据分类ID查询,查询目前正在启售的菜品列表 (已实现)
B. 遍历菜品列表,并查询菜品的分类信息及菜品的口味列表
C. 组装数据DishDto,并返回
1 DishController中增加根据条件查询对应的菜品数的list()方法
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.entity.DishFlavor; 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 { @Autowired private DishService dishService; @Autowired private DishFlavorService dishFlavorService; @Autowired private CategoryService categoryService; @PostMapping public 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); // } @GetMapping("/list") public R<List<DishDto>> 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); List<DishDto> dishDtoList = list.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); } //当前菜品的id Long dishId = item.getId(); LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId); //SQL:select * from dish_flavor where dish_id = ? List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper); dishDto.setFlavors(dishFlavorList); return dishDto; }).collect(Collectors.toList()); return R.success(dishDtoList); } }
2 在SetmealController中创建list()方法,根据条件查询套餐数据。
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.SetmealDto; import com.itheima.reggie.entity.Category; import com.itheima.reggie.entity.Setmeal; import com.itheima.reggie.service.CategoryService; import com.itheima.reggie.service.SetmealDishService; import com.itheima.reggie.service.SetmealService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; 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: 套餐管理 * 不仅需要保存套餐的基本信息,还需要保存套餐关联的菜品数据,所以需要再该方法中调用业务层方法,完成两块数据的保存。 * @version 1.0 * @date 2022/8/19 15:37 */ @RestController @RequestMapping("/setmeal") @Slf4j public class SetmealController { @Autowired private SetmealService setmealService; @Autowired private CategoryService categoryService; @Autowired private 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("新增套餐成功"); } @GetMapping("/page") public R<Page> page(int page,int pageSize,String name){ /**@Description: 套餐分页查询 * @author LiBiGo * @date 2022/8/21 10:40 */ // 分页构造器对象 Page<Setmeal> pageInfo = new Page<>(page,pageSize); Page<SetmealDto> dtoPage = new Page<>(); LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); // 添加查询条件,根据name进行like模糊查询 queryWrapper.like(name!=null,Setmeal::getName,name); // 排序条件,根据更新时间进行降序排序 queryWrapper.orderByDesc(Setmeal::getUpdateTime); setmealService.page(pageInfo,queryWrapper); // 拷贝对象 BeanUtils.copyProperties(pageInfo,dtoPage,"record"); List<Setmeal> records = pageInfo.getRecords(); List<SetmealDto> list = records.stream().map((item) -> { SetmealDto setmealDto = new SetmealDto(); //对象拷贝 BeanUtils.copyProperties(item,setmealDto); //分类id Long categoryId = item.getCategoryId(); //根据分类id查询分类对象 Category category = categoryService.getById(categoryId); if(category != null){ //分类名称 String categoryName = category.getName(); setmealDto.setCategoryName(categoryName); } return setmealDto; }).collect(Collectors.toList()); dtoPage.setRecords(list); return R.success(dtoPage); } @DeleteMapping public R<String> delete(@RequestParam List<Long> ids){ /**@Description: 删除套餐 * @author LiBiGo * @date 2022/8/21 11:35 */ log.info("ids:{}",ids); setmealService.removeWithDish(ids); return R.success("套餐数据删除成功"); } @GetMapping("/list") public R<List<Setmeal>> list(Setmeal setmeal) { /** * 根据条件查询套餐数据 * @param setmeal * @return */ log.info("setmeal:{}", setmeal); //条件构造器 LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(StringUtils.isNotEmpty(setmeal.getName()), Setmeal::getName, setmeal.getName()); queryWrapper.eq(null != setmeal.getCategoryId(), Setmeal::getCategoryId, setmeal.getCategoryId()); queryWrapper.eq(null != setmeal.getStatus(), Setmeal::getStatus, setmeal.getStatus()); queryWrapper.orderByDesc(Setmeal::getUpdateTime); return R.success(setmealService.list(queryWrapper)); } }
3 功能测试
测试过程中可以使用浏览器的监控工具查看页面和服务端的数据交互细节。
点击分类,根据分类查询菜品列表/套餐列表: