苍穹外卖-day04

day-04

25-3-20

新增套餐

需求分析&设计

image-20250321201126408

业务规则

  • 套餐名称唯一
  • 套餐必须属于某个分类
  • 套餐必须包含菜品
  • 名称、分类、价格、图片为必填项
  • 添加菜品窗口需要根据分类类型来展示菜品
  • 新增的套餐默认为停售状态

接口设计(共涉及到4个接口):

  • 根据类型查询分类(已完成)
  • 根据分类id查询菜品
  • 图片上传(已完成)
  • 新增套餐

根据菜品分类id查询菜品

image-20250321202033532

新增套餐

image-20250321202135100

代码开发

1. 根据菜品分类查询菜品

controller

    /**
     *根据分类id查询菜品
     *
     * @return
     */
    //TODO 新增套餐时  搜索框里输入菜品名称进行搜索,前端好像没有写接口,日后再议
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<Dish>> list(Long categoryId){
        log.info("分类id查询菜品: id={}",categoryId);
        List<Dish> list = dishService.list(categoryId);
        return Result.success(list);
    }

service

//接口
    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    List<Dish> list(Long categoryId);




//impl
    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    public List<Dish> list(Long categoryId) {
        Dish dish = Dish.builder()
                .categoryId(categoryId)
                .status(StatusConstant.ENABLE)
                .build();
        return dishMapper.list(dish);
    }

mapper


    /**
     * 动态条件查询菜品
     *
     * @param dish
     * @return
     */
    List<Dish> list(Dish dish);

dishMapper.xml

    <!--动态条件查询菜品-->
    <select id="list" resultType="com.sky.entity.Dish">
        select * from dish
        <where>
            <if test="name != null">
                and name like concar('%',#{name},'%')
            </if>
            <if test="categoryId !=null ">
                and category_id = #{categoryId}
            </if>
            <if test="status !=null ">
                and status = #{status}
            </if>
        </where>
        order by create_time desc
    </select>

2.新增套餐

controller

   //SetmealController
	/**
     * 新增套餐及其对应菜品关系数据
     *
     * @param setmealDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增套餐")
    public Result save(@RequestBody SetmealDTO setmealDTO){
        log.info("新增套餐:{}",setmealDTO);
        setmealService.saveWithDish(setmealDTO);
        return Result.success();
    }

service

//接口
    void saveWithDish(SetmealDTO setmealDTO);



//imple
    /**
     * 新增套餐及其对应菜品关系数据
     * 1.向套餐表中插入数据
     * 2.向套餐菜品关系表中插入多条数据
     *
     * @param setmealDTO
     */
    @Transactional
    public void saveWithDish(SetmealDTO setmealDTO) {
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO,setmeal);
        //向套餐表插入一条数据
        setmealMapper.insert(setmeal);
        //向套餐菜品关系表插入多条数据
        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        //判断是否有菜品数据,并将套餐id填充
        if(setmealDishes != null && setmealDishes.size() > 0){
            setmealDishes.forEach(dish -> dish.setSetmealId(setmeal.getId()));
            //批量插入
            setmealDishMapper.insertBatch(setmealDishes);
        }
    }

mapper

 //SetmealMapper
	/**
     * 新增套餐
     *
     * @param setmeal
     */
    @Insert("insert into setmeal (category_id, name, price, description, image, create_time, update_time, create_user, update_user)" +
            "values (#{categoryId},#{name},#{price},#{description},#{image},#{createTime},#{updateTime},#{createUser},#{updateUser})")
    @AutoFill(value = OperationType.INSERT)
    void insert(Setmeal setmeal);


//SetmealDishMapper
    /**
     * 批量插入套餐菜品关系数据
     *
     * @param setmealDishes
     */
    void insertBatch(List<SetmealDish> setmealDishes);

xml

    <!--批量插入套餐菜品关系数据-->
    <insert id="insertBatch">
        insert into setmeal_dish (setmeal_id, dish_id,name,price,copies) values
        <foreach collection="list" item="sd" separator="," >
             (#{sd.setmealId}, #{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
        </foreach>
    </insert>

遇到的错误

动态sql参考:https://mybatis.net.cn/dynamic-sql.html

参考2:https://blog.csdn.net/weixin_44825912/article/details/130433302

新增套餐 批量插入套餐菜品关系数据 动态sql写错,还是不够熟练

//报错信息
### SQL: insert into setmeal_dish (setmeal_id, dish_id,name,price,copies) values          (              ?, ?,?,?,?)          ,             ?, ?,?,?,?)          ,             ?, ?,?,?,?)          ,             ?, ?,?,?,?)          ,             ?, ?,?,?,?)          ,             ?, ?,?,?,?)          )

动态sql写错。
继续学习动态sql

   <!--批量插入套餐菜品关系数据-->
    <insert id="insertBatch">
        insert into setmeal_dish (setmeal_id, dish_id,name,price,copies) values
        <foreach collection="list" item="sd" open="("  separator="," close=")">
           #{sd.setmealId}, #{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
    </foreach>
        
    <!--修正后-->
   <insert id="insertBatch">
        insert into setmeal_dish (setmeal_id, dish_id,name,price,copies) values
        <foreach collection="list" item="sd" separator="," >
             (#{sd.setmealId}, #{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
        </foreach>
    </insert>

功能测试&提交

功能一:根据菜品分类查询菜品完成

image-20250322104258089

功能二:新增套餐

image-20250322115658577

测试成功提交

套餐分页查询

需求分析&设计

业务规则:

  • 根据套餐名称查询套餐
  • 新增套餐 (已完成)
  • 分页查询菜单
    • 需要关联分类表展示套餐分类id对应的分类名
    • 分页按照创建时间倒序排列

image-20250322194036538

接口设计:

image-20250322194234889

代码开发

controller


//SetmealController
	/**
     * 套餐分页查询
     *
     * @param setmealPageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("套餐分页查询")
    public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO){

        log.info("套餐分页查询信息:{}",setmealPageQueryDTO);
        PageResult pageResult =  setmealService.pageQuery(setmealPageQueryDTO);
        return Result.success(pageResult);

    }

service

//接口
PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);


//impl

    /**
     * 套餐分页查询
     *
     * @param setmealPageQueryDTO
     * @return
     */
    public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {
        PageHelper.startPage(setmealPageQueryDTO.getPage(),setmealPageQueryDTO.getPageSize());
        Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);

        return new PageResult(page.getTotal(),page.getResult());
    }

mapper

    /**
     * 分页查询套餐
     *
     * @param setmealPageQueryDTO
     * @return
     */
    Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);

xml

    <!--分页查询-->
    <select id="pageQuery" resultType="com.sky.vo.SetmealVO">
        select s.*,c.name as categoryName from setmeal s left outer join category c on s.category_id=c.id
        <where>
            <if test="name!=null and name!=''">
                and s.name like concat('%',#{name},'%')
            </if>
            <if test="categoryId!=null">
                and s.category_id=#{categoryId}
            </if>
            <if test="status!=null and status!=''">
                and s.status=#{status}
            </if>
        </where>
        order by s.create_time desc
    </select>

功能测试&提交

测试成功&提交

image-20250322202547643

删除套餐

需求分析&设计

业务规则:

  • 要求实现批量删除
  • 只有停售的套餐才可以被删除
  • 删除套餐要同步批量删除菜品套餐关系表中的对应数据

image-20250322205308466

接口设计:

image-20250322205902414

代码开发

补充:Objects.equals(a,b)的作用与原理

1.作用:

  • 用于安全的比较两个对象是否相等,避免NullpointerException

  • 源码image-20250323114930275


controller

    /**
     * 批量删除套餐
     *
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("批量删除套餐")
    public Result delete(@RequestParam List<Long> ids){
        log.info("删除套餐:{}", ids);
        setmealService.deleteBatch(ids);
        return Result.success();
    }

service

//接口
	/**
     * 根据id批量删除套餐
     *
     * @param ids
     */
    void deleteBatch(List<Long> ids);

//impl
	/**
     * 批量删除套餐
     *
     * @param ids
     */
    @Override
    @Transactional
    public void deleteBatch(List<Long> ids) {
        //1.判断当前套餐是否在启售中
        for (Long id : ids){
            //根据套餐id查询套餐信息
            Setmeal setmeal = setmealMapper.getByid(id);
            //判断状态不为空,并且等于1 为启售中    启售中菜品不能删除
            if (Objects.equals(setmeal.getStatus(), StatusConstant.ENABLE)) {
                throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
            }

        }

        //2.删除套餐表中对应的数据
        setmealMapper.deleteByIds(ids);

        //3.删除套餐菜品关系表中对应数据
        setmealDishMapper.deleteBySetmealIds(ids);
    }

mapper

//setmealMapper
    /**
     * 根据套餐id查询套餐信息
     *
     * @param id
     * @return
     */
    @Select("select * from setmeal where id = #{id}")
    Setmeal getByid(Long id);


    /**
     * 删除套餐表中对应数据
     *
     * @param ids
     */
    void deleteByIds(List<Long> ids);


//setmealDishMapper
    /**
     * 根据套餐id批量删除套餐菜品关系数据
     *
     * @param setmealIds
     */
    void deleteBySetmealIds(List<Long> setmealIds);

sr.xml

<!--setmealMapepr.xml-->
    <!--删除套餐表中对应数据-->
    <delete id="deleteByIds">
        delete from setmeal where id in
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>


<!--setmealDishMapper-->
<!--根据套餐id批量删除套餐菜品关系数据-->
    <delete id="deleteBySetmealIds">
        delete from setmeal_dish where setmeal_id in
        <foreach collection="setmealIds" item="setmealId" open="(" separator="," close=")">
            #{setmealId}
        </foreach>
    </delete>

功能测试&提交

测试成功

image-20250323005051809

修改套餐

需求分析&设计

业务规则:

  • 套餐信息回显,根据套餐id查询套餐
  • 接受前端DTO对象并修改
image-20250323120809520

接口设计:

image-20250323120757172 image-20250323120922106

遇到错误错误

回显数据时不能回显套餐关联的菜品信息, 猜测可能是新增套餐时没有新增套餐和菜品关联关系的原因

setmeal_dish

image-20250323135733332

果然是因为前面新增套餐时有bug,没有将套餐和菜品之间的关联关系插入

,现在回显还是有问题,但属于回显的问题---->查询,OK

果不其然,因为前面以为是回显查询sql出了问题,所有修改了sql,后面忘记了,现在修改回去就好了


代码开发

修改业务 & 回显数据:

SetmealController

	/**
     * 回显套餐数据
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询套餐数据")
    public Result<SetmealVO> getById(@PathVariable Long id){
        log.info("根据id查询套餐数据:id={}", id);
        SetmealVO setmealVO = setmealService.getByIdWithDish(id);
        return Result.success(setmealVO);
    }    



	@PutMapping
    @ApiOperation("修改套餐")
    public Result update(@RequestBody SetmealDTO setmealDTO){
        log.info("修改套餐:{}",setmealDTO);
        setmealService.update(setmealDTO);
        return Result.success();
    }

SetmealSerivce

    /**
     * 根据id查询套餐和菜品的关联关系
     *
     * @param id
     * @return
     */
    SetmealVO getByIdWithDish(Long id);  	

	/**
     * 根据id查询套餐和套餐菜品关系
     *
     * @param id
     * @return
     */
    public SetmealVO getByIdWithDish(Long id){
        //根据id查询套餐基本信息
        Setmeal setmeal = setmealMapper.getById(id);
        SetmealVO setmealVO = new SetmealVO();

        //根据id查询套餐和菜品的关联关系
        List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);

        //将基本信息拷贝到VO中,给VO设置套餐和菜品的关联关系
        BeanUtils.copyProperties(setmeal,setmealVO);
        setmealVO.setSetmealDishes(setmealDishes);

        return setmealVO;
    }




	/**
     * 修改套餐
     *
     * @param setmealDTO
     */
    void update(SetmealDTO setmealDTO);

//impl

    /**
     * 修改套餐
     *
     * @param setmealDTO
     */
    @Transactional
    public void update(SetmealDTO setmealDTO) {
        Setmeal setmeal = new Setmeal();
        BeanUtils.copyProperties(setmealDTO, setmeal);

        //1、修改套餐表,执行update
        setmealMapper.update(setmeal);

        //套餐id
        Long setmealId = setmealDTO.getId();

        //2、删除套餐和菜品的关联关系,操作setmeal_dish表,执行delete
        setmealDishMapper.deleteBySetmealId(setmealId);

        List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
        setmealDishes.forEach(setmealDish -> {
            setmealDish.setSetmealId(setmealId);
        });
        //3、重新插入套餐和菜品的关联关系,操作setmeal_dish表,执行insert
        setmealDishMapper.insertBatch(setmealDishes);
    }

mapper



//setmealDishMapper
    /**
     * 根据id查询套餐和菜品的关联关系
     *
     * @param setmealId
     * @return
     */
    @Select("select * from setmeal_dish where setmeal_id = #{setmealId}")
    List<SetmealDish> getBySetmealId(Long setmealId);




    /**
     * 删除套餐关联id
     *
     * @param id
     */
    @Delete("delete from setmeal_dish where setmeal_id = #{id}")
    void deleteBySetmealId(Long id);



//setmealMapper
    /**
     *根据套餐id查询套餐信息
     *
     * @param id
     * @return
     */
    @Select("select * from setmeal where id = #{id}")
    Setmeal getById(Long id);




    /**
     * 修改套餐
     *
     * @param setmeal
     */
    @AutoFill(OperationType.UPDATE)
    void update(Setmeal setmeal);


<!--动态 xml-->
    <update id="update">
        update setmeal
        <set>
            <if test="categoryId!=null">
                category_id=#{categoryId},
            </if>
            <if test="name!=null and name!=''">
                name=#{name},
            </if>
            <if test="price!=null">
                price=#{price},
            </if>
            <if test="image!=null and image!=''">
                image=#{image},
            </if>
            <if test="description!=null and description!=''">
                description=#{description},
            </if>
            <if test="updateTime!=null">
                update_time=#{updateTime},
            </if>
            <if test="updateUser!=null and updateUser!=''">
                update_user=#{updateUser},
            </if>
            <if test="status!=null">
                status=#{status},
            </if>
        </set>
        where id=#{id}
    </update>

功能测试&提交

测试成功& 提交

image-20250323162622519

启售停售套餐

需求分析&设计

  • 菜品停售会关联套餐停售
  • 而套餐可以随意停售,不会影响单独菜品

所以我应该先写套餐停售


  • 可以对状态为起售的套餐进行停售操作,可以对状态为停售的套餐进行起售操作
  • 起售的套餐可以展示在用户端,停售的套餐不能展示在用户端
  • 起售套餐时,如果套餐内包含停售的菜品,则不能起售

接口设计:

image-20250323163600199

代码开发

controller

    /**
     * 套餐启用 & 禁用
     *
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("套餐启用禁用")
    public Result status(@PathVariable Integer status,Long id){
        log.info("修改套餐为{}状态",status == StatusConstant.ENABLE ? "启售" : "停售");
        setmealService.startOrStop(status,id);
        return Result.success();
    }

service

    /**
     * 套餐启售停售
     *
     * @param status
     * @param id
     */
    void startOrStop(Integer status,Long id);


    /**
     * 套餐启售停售
     *
     * @param status
     * @param id
     */
    @Override
    public void startOrStop(Integer status, Long id) {
        //起售套餐时,判断套餐内是否有停售菜品,有停售菜品提示"套餐内包含未启售菜品,无法启售"
        //如果前端传过来要修改的状态为启售,那么我要继续检查该套餐里的菜品是否含有禁售菜品,如果有,抛出异常 +++
        if(status == StatusConstant.ENABLE){
            //select a.* from dish a left join setmeal_dish b on a.id = b.dish_id where b.setmeal_id = ?
            //查询该套餐包含的所有菜品 ,然后检查菜品状态是否为禁售
            List<Dish> dishList = dishMapper.getBySetmealId(id);
            if(dishList != null && dishList.size() > 0){
                dishList.forEach(dish -> {
                    if(StatusConstant.DISABLE == dish.getStatus()){
                        throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);
                    }
                });
            }
        }

        //+++ 如果没有 就修改状态
        Setmeal setmeal = Setmeal.builder()
                .id(id)
                .status(status)
                .build();
        setmealMapper.update(setmeal);
    }

mapper

//DishMapper

	/**
     *根据id查询菜品信息
     *
     * @param id
     * @return
     */
    @Select("select a.* from dish a left join setmeal_dish b on a.id = b.dish_id where b.setmeal_id = #{id}")
    List<Dish>  getBySetmealId(Long id);


//setmealMapper
    /**
     * 修改套餐
     *
     * @param setmeal
     */
    @AutoFill(OperationType.UPDATE)
    void update(Setmeal setmeal);


//服用之前的修改套餐SetmealMapper的update即可
    <!--动态 xml-->
    <update id="update">
        update setmeal
        <set>
            <if test="categoryId!=null">
                category_id=#{categoryId},
            </if>
            <if test="name!=null and name!=''">
                name=#{name},
            </if>
            <if test="price!=null">
                price=#{price},
            </if>
            <if test="image!=null and image!=''">
                image=#{image},
            </if>
            <if test="description!=null and description!=''">
                description=#{description},
            </if>
            <if test="updateTime!=null">
                update_time=#{updateTime},
            </if>
            <if test="updateUser!=null and updateUser!=''">
                update_user=#{updateUser},
            </if>
            <if test="status!=null">
                status=#{status},
            </if>
        </set>
        where id=#{id}
    </update>

功能测试&提交

image-20250323170550576

补充一个菜品停售

  • 因为写了套餐停售才能写菜品停售

controller

    /**
     * 启用或禁用菜品
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("启用或禁用菜品")
    public Result status(@PathVariable Integer status,Long id){
        dishService.startOrStop(status,id);
        return Result.success();
    }

service

    /**
     * 菜品启售 禁售
     *
     * @param status
     * @param id
     */
    void startOrStop(Integer status, Long id);   



	/**
     * 启用或禁用菜品
     *
     * @param status
     * @param id
     */
    @Override
    public void startOrStop(Integer status, Long id) {
        Dish dish = Dish.builder().status(status).id(id).build();
        dishMapper.update(dish);
    }

mapper

    /**
     * 根据id更新菜品
     *
     * @param dish
     */
    @AutoFill(OperationType.UPDATE)
    void update(Dish dish);

<!--根据菜品id 动态修改菜品-->
    <update id="update">
        update dish
        <set>
            <if test="name!=null and name!=''">
                name=#{name},
            </if>
            <if test="categoryId!=null">
                category_id=#{categoryId},
            </if>
            <if test="price!=null">
                price=#{price},
            </if>
            <if test="image!=null and image!=''">
                image=#{image},
            </if>
            <if test="description!=null and description!=''">
                description=#{description},
            </if>
            <if test="updateTime!=null">
                update_time=#{updateTime},
            </if>
            <if test="updateUser!=null and updateUser!=''">
                update_user=#{updateUser},
            </if>
            <if test="status!=null">
                status=#{status},
            </if>
        </set>
        where id=#{id}
    </update>
posted @ 2025-03-23 17:18  han390  阅读(657)  评论(0)    收藏  举报