基于Springboot外卖系统20:前端菜品展示+菜品数量查询

本文主要是介绍基于Springboot外卖系统20:前端菜品展示+菜品数量查询,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 {@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);
//    }@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);}//当前菜品的idLong 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 {@Autowiredprivate SetmealService setmealService;@Autowiredprivate CategoryService categoryService;@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("新增套餐成功");}@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);//分类idLong 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);}@DeleteMappingpublic 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 功能测试

测试过程中可以使用浏览器的监控工具查看页面和服务端的数据交互细节。

 点击分类,根据分类查询菜品列表/套餐列表:

 

 

这篇关于基于Springboot外卖系统20:前端菜品展示+菜品数量查询的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/375140

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

部署Vue项目到服务器后404错误的原因及解决方案

《部署Vue项目到服务器后404错误的原因及解决方案》文章介绍了Vue项目部署步骤以及404错误的解决方案,部署步骤包括构建项目、上传文件、配置Web服务器、重启Nginx和访问域名,404错误通常是... 目录一、vue项目部署步骤二、404错误原因及解决方案错误场景原因分析解决方案一、Vue项目部署步骤

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.