套餐管理业务开发_数据

1. 新增套餐  5-2

1.1 需求分析  5-2

套餐管理业务开发_List_02

1.2 数据模型  5-2

新增套餐,其实就是将新增页面录入的套餐信息插入到setmeal表,还需要向setmeal dish表插入套餐和菜品关联数据。

所以在新增套餐时,涉及到两个表:

●  setmeal 套餐表

● setmeal _dish 套餐菜品关系表

套餐管理业务开发_List_03

套餐管理业务开发_List_04

1.3 代码开发  5-3

1.3.1 代码开发-准备工作  5-3

在开发业务功能前,先将需要用到的类和接口基本结构创建好:

●实体类SetmealDish (直接从课程资料中导入即可,Setmeal实体前面课程中已经导入过了)

●DTO SetmealDto (直接从课程资料中导入即可)

●Mapper接 口SetmealDishMapper

●业务层接口SetmealDishService

●业务层实现类SetmealDishServicelmpl

●控制层SetmealController

套餐菜品关系实体类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;

/**
 * 套餐菜品关系  5-3
 */
@Data
public class SetmealDish implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //套餐id
    private Long setmealId;


    //菜品id
    private 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;
}
数据传输对象DTO   SetmealDto
package com.itheima.reggie.dto;

import com.itheima.reggie.entity.Setmeal;
import com.itheima.reggie.entity.SetmealDish;
import lombok.Data;
import java.util.List;

//数据传输对象DTO  5-3
@Data
public class SetmealDto extends Setmeal {

    private List<SetmealDish> setmealDishes;

    private String categoryName;
}

套餐管理持久层接口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;

//套餐管理持久层接口  5-3
@Mapper
public interface SetmealDishMapper extends BaseMapper<SetmealDish> {
}

套餐管理业务层接口SetmealDishService
package com.itheima.reggie.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.itheima.reggie.entity.SetmealDish;

//套餐管理业务层接口  5-3
public interface SetmealDishService extends IService<SetmealDish> {
}

套餐管理业务层接口实现类SetmealDishServiceImpl
package com.itheima.reggie.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
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;

//套餐管理业务层接口实现类  5-3
@Service
@Slf4j
public class SetmealDishServiceImpl extends ServiceImpl<SetmealDishMapper,SetmealDish> implements SetmealDishService {
}

套餐管理控制层SetmealController
package com.itheima.reggie.controller;

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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//套餐管理控制层  5-3
@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {
    @Autowired
    private SetmealService setmealService;
    @Autowired
    private SetmealDishService setmealDishService;
}

1.3.2 业务开发

在开发代码之前,需要梳理一下 新增套餐时前端页面和服务端的交互过程:

1、页面(backend/ page/ combo/add.html)发送ajax请求, 请求服务端获取套餐分类数据并展示到下拉框中

2、页面发送ajax请求,请求服务端获取菜品分类数据并展示到添加菜品窗口中

3、页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中

4、页面发送请求进行图片上传,请求服务端将图片保存到服务器

5、页面发送请求进行图片下载,将上传的图片进行回显

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

开发新增套餐功能,其实就是在服务端编写代码去处理前端页面发送的这6次请求即可。

根据菜品分类的id查询菜品  5-4

套餐管理业务开发_业务层_05

套餐管理业务开发_业务层_06

菜品管理DishController
 //根据菜品分类的id查询菜品  5-4
    @GetMapping("/list")
    public R<List<Dish>> list(Dish dish){
        //构造查询条件对象
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
        //添加条件,查询状态为1的也就是起售的菜品
        queryWrapper.eq(Dish::getStatus,1);

        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishService.list(queryWrapper);

        return R.success(list);
    }

套餐管理业务开发_List_07

新增套餐业务开发  5-5   5-6

套餐管理业务开发_List_08

套餐管理业务开发_数据_09

注意setmealId没有赋值所以代码中我们需要手动赋值

套餐管理业务开发_业务层_10

套餐管理业务层接口SetmealService
/**
     * 新增套餐,同时需要保存套餐和菜品的关联关系   5-6
     * @param setmealDto
     */
    public void saveWithDish(SetmealDto setmealDto);
套餐管理业务层接口实现类SetmealServiceImpl
@Autowired
    private SetmealDishService setmealDishService;

    //新增套餐,同时需要保存套餐和菜品的关联关系   5-6
    @Override
    @Transactional //事务
    public void saveWithDish(SetmealDto setmealDto) {

        //保存套餐的基本信息,操作setmeal,执行insert操作
        this.save(setmealDto);

        //保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        //因为通过debug看到套餐id  setmealId没有赋值,所以我们需要手动添加
        setmealDishes = setmealDishes.stream().map((item)->{
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());

        setmealDishService.saveBatch(setmealDishes);

    }
套餐管理控制层SetmealController
 //新增套餐  5-5  5-6
    @PostMapping
    public R<String> save(@RequestBody SetmealDto setmealDto){
        log.info("套餐信息 {}",setmealDto);

        setmealService.saveWithDish(setmealDto);

        return R.success("新增套餐成功");
    }

测试成功

套餐管理业务开发_业务层_11

套餐管理业务开发_业务层_12

套餐管理业务开发_List_13

2. 套餐信息的分页查询  5-8

2.1 需求分析  5-8

套餐管理业务开发_业务层_14

2.2 代码开发-梳理交互过程  5-8

在开发代码之前,需要梳理一下套餐分页查询时前端页面和服务端的交互过程:

1、页面(backend/page/combo/list.html)发送ajax请求, 将分页查询参数(page、pageSize、

name)提交到服务端,获取分页数据

2、页面发送请求,请求服务端进行图片下载,用于页面图片展示

开发套餐信息分页查询功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。

2.3 代码开发   5-9

套餐管理业务开发_业务层_15

套餐管理业务开发_List_16

依然存在和菜品分页查询一样的问题,解决方法也是一样的

套餐管理业务开发_数据_17

套餐管理业务开发_List_18

套餐管理控制层SetmealController
//方便我们做套餐分页查询时使用  5-9
    @Autowired
    private CategoryService categoryService;
套餐管理控制层SetmealController
//套餐信息分页查询  5-9
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){

        //分页构造器
        Page<Setmeal> pageInfo = new Page<>();

        Page<SetmealDto> setmealDtoPage = new Page<>();

        //添加查询条件
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件 根据名字进行like模糊查询
        queryWrapper.like(name!=null,Setmeal::getName,name);
        //添加排序条件,根据更新时间降序排列
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        //执行分页查询
        //这条语句会将我们查询到的数据进行封装 全部封装进Page的对象pageInfo
        setmealService.page(pageInfo,queryWrapper);

        //此时这个情况和菜品的分页查询一样的原因,我们这里套餐分类的名字显示不出来因为
        // 我们传的是id,而前端需要的是name 解决办法和菜品的分页查询一样

        //拷贝pageInfo给setmealDtoPage,但是不拷贝records,因为pageInfo对应的泛型是Setmeal
        //而我们需要的是SetmealDto
        //这个拷贝也只是拷贝page对象的普通属性不包括records属性集合
        BeanUtils.copyProperties(pageInfo,setmealDtoPage,"records");

        List<Setmeal> records = pageInfo.getRecords();

        List<SetmealDto> list = records.stream().map((item)->{
            //这个setmealDto是我们新new出来的,里面的属性都是空的,需要我们给赋值
            SetmealDto setmealDto = new SetmealDto();
            //将Setmeal的普通属性拷贝给setmealDto
            BeanUtils.copyProperties(item,setmealDto);

            //得到套餐分类id
            Long categoryId = item.getCategoryId();
            //根据套餐分类id查询出分类对象
            Category category = categoryService.getById(categoryId);
            if(category!=null){
                //得到套餐分类的名称
                String categoryName = category.getName();
                //将分类名赋值给setmealDto对象
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());//将这些setmealDto对象收集起来封装成集合

        //经过上面一番操作我们就得到了带有 套餐分类名称 的 泛型为setmealDto 的集合

        setmealDtoPage.setRecords(list);//给setmealDtoPage的records赋值
        
        return R.success(setmealDtoPage);
    }

3. 删除套餐  5-10

3.1 业务需求  5-10

套餐管理业务开发_业务层_19

3.2 代码开发-梳理交互过程  5-10

套餐管理业务开发_List_20

3.3 代码开发  5-11

删除单个套餐

套餐管理业务开发_List_21

套餐管理业务开发_List_22

删除多个套餐

套餐管理业务开发_业务层_23

套餐管理业务层接口SetmealService

 /**
     * 删除套餐,同时需要删除套餐和菜品的关联数据   5-11
     * @param ids
     */
    public void removeWithDish(List<Long> ids);

套餐管理业务层接口实现类SetmealServiceImpl

/**
     * 删除套餐,同时需要删除套餐和菜品的关联数据  5-11
     * @param ids
     */
    @Transactional
    public void removeWithDish(List<Long> ids) {
        
        //查询套餐状态,确定是否可用删除
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper();
        //select count(*) from setmeal where id in (1,2,3) and status = 1
        queryWrapper.in(Setmeal::getId,ids);
        queryWrapper.eq(Setmeal::getStatus,1);
        //这里的思想是根据id和status查询,如果查询出来的数据大于0,就证明处于售卖状态,否则为停售状态
        int count = this.count(queryWrapper);
        if(count > 0){
            //如果不能删除,抛出一个业务异常
            throw new CustomException("套餐正在售卖中,不能删除");
        }

        //如果可以删除,先删除套餐表中的数据---setmeal
        this.removeByIds(ids);
        
        LambdaQueryWrapper<SetmealDish> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        
        //delete from setmeal_dish where setmeal_id in (1,2,3)
        lambdaQueryWrapper.in(SetmealDish::getSetmealId,ids);
        //删除关系表中的数据----setmeal_dish
        setmealDishService.remove(lambdaQueryWrapper);
    }

套餐管理控制层SetmealController

/**
     * 删除套餐
     * @param ids
     * @return
     */
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids){
        log.info("ids:{}",ids);

        setmealService.removeWithDish(ids);

        return R.success("套餐数据删除成功");
    }

测试

套餐管理业务开发_业务层_24

套餐管理业务开发_List_25

套餐管理业务开发_业务层_26

4. 拓展,修改套餐  自己实现 代码在reggie_take_out5_1中

分两步实现

4.1 首先是将数据回显

这个和菜品修改原理一模一样

套餐管理业务开发_业务层_27

套餐管理业务层接口SetmealService

//根据套餐id来查询菜品信息和口味信息   自己实现
    public SetmealDto getByIdWithDish(Long id);

套餐管理业务层接口实现类SetmealServiceImpl

//根据套餐id查询套餐数据和对应的菜品   回显数据   自己实现
    @Override
    public SetmealDto getByIdWithDish(Long id) {
        //因为没有SetmealDto这张表,所以我们分两张表查询,一个是Setmeal表一个是SetmealDish表
        //首先查询Setmeal表,查到套餐的基本数据不包括套餐对应的菜品
        Setmeal setmeal = this.getById(id);

        //new一个SetmealDto出来因为我们最终要返回的是SetmealDto因为它里面包括了套餐
        // 的基本数据还有对应的菜品
        //我们刚new出来的SetmealDto是空的,所以需要将查询到的数据设置进去
        SetmealDto setmealDto = new SetmealDto();
        BeanUtils.copyProperties(setmeal,setmealDto);

        //接着查询套餐菜品关系表,查出对应的菜品
        //因为我们的参数id数套餐的id不是套餐菜品关系表的id,所以自己构造查询条件
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
        //使用套餐表id查询套餐菜品关系表
        queryWrapper.eq(SetmealDish::getSetmealId,id);
        List<SetmealDish> list = setmealDishService.list(queryWrapper);//查出来肯定是集合

        //将查出来的对应菜品放进setmealDto
        setmealDto.setSetmealDishes(list);

        return setmealDto;
    }

SetmealController

//修改套餐 之回显数据     自己实现的
    //根据套餐id来查询套餐信息和菜品信息
    @GetMapping("/{id}")
    public R<SetmealDto> get(@PathVariable Long id){

        //调用我们自己实现的方法,因为修改套餐涉及两张表
        SetmealDto setmealDto = setmealService.getByIdWithDish(id);

        return R.success(setmealDto);
    }

4.2 保存修改

这个也是和修改菜品原理一样

套餐管理业务开发_业务层_28

套餐管理业务开发_List_29

套餐管理业务层接口SetmealService

//更新套餐信息 同时更新菜品信息 自己实现
    public void updateWithDish(SetmealDto setmealDto);

套餐管理业务层接口实现类SetmealServiceImpl

//更新套餐信息同时更新对应菜品   自己实现
    @Override
    @Transactional
    public void updateWithDish(SetmealDto setmealDto) {
        //还是一样分两张表来做
        //首先更新套餐表
        this.updateById(setmealDto);

        //更新套餐菜品关系表
        //这里我们直接根据套餐id删除原来的菜品,在添加即可
        LambdaQueryWrapper<SetmealDish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SetmealDish::getSetmealId,setmealDto.getId());
        setmealDishService.remove(queryWrapper);

        //往餐菜品关系表添加新数据
        List<SetmealDish> setmealDishes = setmealDto.getSetmealDishes();
        //这里和添加一样的问题  继续为餐菜品关系表添加套餐id
        setmealDishes = setmealDishes.stream().map((item)->{
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());

        setmealDishService.saveBatch(setmealDishes);

    }

SetmealController

//更新套餐信息 自己实现
    @PutMapping
    public R<String> update(@RequestBody SetmealDto setmealDto){

        //调用我们自己实现的方法,因为修改套餐涉及两张表
        setmealService.updateWithDish(setmealDto);

        return R.success("套餐修改成功");
    }

5. 拓展  停售起售状态修改  自己实现  代码在reggie_take_out5_1

停售

套餐管理业务开发_数据_30

套餐管理业务开发_业务层_31

起售

套餐管理业务开发_业务层_32

套餐管理业务开发_List_33

批量停售

套餐管理业务开发_业务层_34

套餐管理业务开发_List_35

批量起售

套餐管理业务开发_数据_36

套餐管理业务开发_业务层_37

由上图可以这四种功能的请求路径都是一样的,且均使用了restful风格

套餐管理业务层接口SetmealService

 //批量停售起售  自己实现
    public void stop(int status,List<Long> ids);

套餐管理业务层接口实现类SetmealServiceImpl

 @Autowired
    private SetmealService setmealService;

    //批量停售起售  自己实现
    @Override
    public void stop(int status,List<Long> ids) {
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Setmeal::getId,ids);//先构造id(可能一个也可能多个,因为我们单独停售起售和批量写一起了)

        //在构造售卖状态
        Setmeal setmeal = new Setmeal();
        setmeal.setStatus(status);

        setmealService.update(setmeal,queryWrapper);

    }

SetmealController

//套餐的起售停售 批量停售 批量起售   自己实现
    @PostMapping("/status/{status}")
    public R<String> update(@PathVariable int status,@RequestParam List<Long> ids){

        //调用我们的方法
        setmealService.stop(status,ids);

        return R.success("套餐售卖修改成功");
    }

测试成功

套餐管理业务开发_业务层_38

套餐管理业务开发_业务层_39

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6