【项目实战 Day4】springboot + vue 苍穹外卖系统(套餐模块 完结)
苍穹外卖项目开发训练day4内容,包含【套餐管理模块】的代码开发内容,保姆级笔记教程!
目录
一、套餐管理模块
1、新增套餐模块
实现新增套餐功能,需要实现以下2个接口:
- 根据分类id查询菜品:用于套餐中添加菜品功能
- 新增套餐


(1)根据分类id查询菜品 - GET接口
【1】controller层
/** * 根据分类id查询菜品 * @param categoryId * @return */ @GetMapping("/list") @ApiOperation("根据分类id查询菜品") public Result<List<Dish>> list(Long categoryId){ List<Dish> list = dishService.getByCategoryId(categoryId); return Result.success(list); }【2】service层
注意:只能返回【起售状态】的菜品
/** * 动态条件查询菜品 * @param categoryId * @return */ public List<Dish> getByCategoryId(Long categoryId) { //只能返回【起售状态】的菜品,因此匹配条件为【分类id】和【status=1】 Dish dish = Dish.builder() .status(StatusConstant.ENABLE) .categoryId(categoryId) .build(); List<Dish> list = dishMapper.list(dish); return list; }【3】mapper层
/** * 根据分类id查询菜品 * @param dish * @return */ List<Dish> list(Dish dish);【4】mybatis文件
<select id="list" resultType="com.sky.entity.Dish"> select * from sky_take_out.dish <where> <if test="name != null">and name like concat('%',#{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)新增套餐 - POST接口
【1】controller层
/** * 新增套餐 * @param setmealDTO * @return */ @PostMapping @ApiOperation("新增套餐") public Result save(@RequestBody SetmealDTO setmealDTO){ log.info("新增套餐:{}",setmealDTO); setmealService.saveWithDish(setmealDTO); return Result.success(); }【2】service层
- 和新增菜品功能类似,前端传来的DTO包含【套餐信息】+【套餐对应菜品列表】
- 我们需要将其拆开,分别加入套餐表和套餐菜品关系表
- 注意:insert操作不会主动返回已插入的套餐id,而套餐菜品表需要获得套餐id,因此我们在insert的xml语句中加入相关属性,获取套餐id,并将套餐id遍历附给每一个对应菜品,最后将绑定套餐id的菜品表插入套餐菜品关系表中
/** * 新增套餐 * @param setmealDTO */ public void saveWithDish(SetmealDTO setmealDTO) { //SetmealDTO中包含:套餐信息+套餐对应菜品列表 //1.把套餐信息拆出来加入套餐表 Setmeal setmeal = new Setmeal(); BeanUtils.copyProperties(setmealDTO,setmeal); setmealMapper.insert(setmeal); //2.因为insert操作不会自动返回套餐id,而套餐菜品表需要套餐id,因此我们要接收一下套餐id Long setmealId = setmeal.getId(); //3.把套餐对应菜品列表拆出来 List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes(); //4.给每个菜品附上套餐id if(setmealDishes != null && setmealDishes.size() > 0){ setmealDishes.forEach(setmealDish -> { setmealDish.setSetmealId(setmealId); }); //5.把菜品加入套餐菜品表 setmealDishMapper.insertBatch(setmealDishes); } }【3】mapper层
1)SetmealMapper
/** * 新增套餐 * @param setmeal */ @AutoFill(value = OperationType.INSERT) void insert(Setmeal setmeal);2)SetmealDishMapper
/** * 批量插入菜品与套餐关系 * @param setmealDishes */ void insertBatch(List<SetmealDish> setmealDishes);【4】mybatis文件
1)SetmealMapper
<insert id="insert" useGeneratedKeys="true" keyProperty="id"> insert into sky_take_out.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}) </insert>2)SetmealDishMapper
<insert id="insertBatch" parameterType="list"> insert into setmeal_dish(setmeal_id, dish_id, name, price, copies) values <foreach collection="setmealDishes" item="sd" separator=","> (#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies}) </foreach> </insert>
2、套餐分页查询 - GET接口
【1】controller层
/** * 套餐分页查询 * @param setmealPageQueryDTO * @return */ @GetMapping("/page") @ApiOperation("套餐分页查询") public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO){ log.info("菜品分类查询:{}",setmealPageQueryDTO); PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO); return Result.success(pageResult); }【2】service层
/** * 套餐分页查询 * @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()); }【3】mapper层
/** * 套餐分页查询 * @param setmealPageQueryDTO * @return */ Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);【4】mybatis文件
因为接口要求:返回的数据包括【套餐信息】+【分类名称】,而套餐表中仅有【分类id】
因此我们需要采用左外连接(返回左表全部记录和右表匹配记录,右表无匹配则显示NULL)进行多表联查(以分类id为外键关联套餐表和分类表)
这样我们就可以获得【套餐信息】+【分类名称】
<select id="pageQuery" resultType="com.sky.vo.SetmealVO"> select s.*,c.name categoryName from sky_take_out.setmeal s left outer join sky_take_out.category c on s.category_id = c.id <where> <if test="name != null">and s.name like concat('%',#{name},'%')</if> <if test="status != null">and s.status = #{status}</if> <if test="categoryId != null">and s.category_id = #{categoryId}</if> </where> order by s.create_time desc </select>
3、删除套餐 - DELETE接口
起售中的套餐不允许删除
【1】controller层
/** * 批量删除套餐 * @param ids * @return */ @DeleteMapping @ApiOperation("批量删除套餐") public Result delete(@RequestParam List<Long> ids){ log.info("批量删除:{}",ids); setmealService.deleteBatch(ids); return Result.success(); }【2】service层
/** * 批量删除套餐 * @param ids */ public void deleteBatch(List<Long> ids) { //起售中的套餐不能删除 for (Long id : ids) { Setmeal setmeal = setmealMapper.getById(id); if(setmeal.getStatus() == StatusConstant.ENABLE){ throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE); } } //批量删除套餐 setmealMapper.deleteBatch(ids); //批量删除套餐菜品关系 setmealDishMapper.deleteByDishBatch(ids); }【3】mapper层
1)SetmealMapper
/** * 批量删除套餐 * @param SetmealIds */ void deleteBatch(List<Long> SetmealIds);2)SetmealDishMapper
/** * 批量删除套餐菜品关系 * @param SetmealIds */ void deleteByDishBatch(List<Long> SetmealIds);【4】mybatis文件
1)SetmealMapper
<delete id="deleteBatch"> delete from sky_take_out.setmeal where id in <foreach collection="SetmealIds" item="id" open="(" close=")" separator=","> #{id} </foreach> </delete>2)SetmealDishMapper
<delete id="deleteByDishBatch"> delete from setmeal_dish where setmeal_id in <foreach collection="SetmealIds" item="setmealId" open="(" close=")" separator=","> #{setmealId} </foreach> </delete>
4、根据id查询套餐 - GET接口
为了使修改页面,数据可以回显,我们需要通过套餐id查询套餐信息+对应套餐菜品信息
【1】controller层
/** * 根据id查询套餐 * @param id * @return */ @GetMapping("/{id}") @ApiOperation("根据id查询套餐") public Result<SetmealVO> getById(@PathVariable Long id){ SetmealVO setmealVO = setmealService.getById(id); return Result.success(setmealVO); }【2】service层
要求返回【套餐信息】+【套餐包含的菜品列表】,因此分别查询最后再合并
/** * 根据id查询套餐 * @param id * @return */ public SetmealVO getById(Long id) { //1.先查询套餐信息 Setmeal setmeal = setmealMapper.getById(id); //2.再查询套餐对应菜品 List<SetmealDish> setmealDishes = setmealDishMapper.getDishBysetmealId(id); //3.合并 SetmealVO setmealVO = new SetmealVO(); BeanUtils.copyProperties(setmeal,setmealVO); setmealVO.setSetmealDishes(setmealDishes); return setmealVO; }【3】mapper层
1)SetmealDishMapper
/** * 根据套餐id获取菜品列表 * @param setmealId * @return */ @Select("select * from sky_take_out.setmeal_dish where setmeal_id = #{setmealId}") List<SetmealDish> getDishBysetmealId(Long setmealId);页面成功回显
5、修改套餐 - PUT接口
【1】controller层
/** * 修改套餐 * @param setmealDTO * @return */ @PutMapping @ApiOperation("修改套餐") public Result update(@RequestBody SetmealDTO setmealDTO){ log.info("修改套餐信息:{}",setmealDTO); setmealService.update(setmealDTO); return Result.success(); }【2】service层
- setmealDTO中包含【套餐信息】和【对应菜品列表】,因此分开修改,先修改套餐信息
- 因为套餐中菜品修改操作会涉及删除和修改,因此我们只需要先把套餐中所有菜品删除,再批量插入即可
/** * 修改套餐 * @param setmealDTO */ public void update(SetmealDTO setmealDTO) { //1.先修改套餐信息 Setmeal setmeal = new Setmeal(); BeanUtils.copyProperties(setmealDTO,setmeal); setmealMapper.update(setmeal); //2.先删除现在套餐内所有菜品 setmealDishMapper.deleteBySetmealId(setmealDTO.getId()); //3.再重新插入套餐对应菜品 List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes(); //逐一绑定菜品对应套餐id if(setmealDishes != null && setmealDishes.size() > 0){ setmealDishes.forEach(setmealDish -> { setmealDish.setSetmealId(setmealDTO.getId()); }); } setmealDishMapper.insertBatch(setmealDishes); }【3】mapper层
1)SetmealMapper
/** * 修改套餐信息 * @param setmeal */ @AutoFill(value = OperationType.UPDATE) void update(Setmeal setmeal);2)SetmealDishMapper
/** * 根据套餐id删除套餐菜品关系 * @param setmealId */ @Delete("delete from sky_take_out.setmeal_dish where setmeal_id = #{setmealId}") void deleteBySetmealId(Long setmealId);【4】mybatis文件
1)SetmealMapper
<update id="update"> update sky_take_out.setmeal <set> <if test="name != null">name = #{name},</if> <if test="categoryId != null">category_id = #{categoryId},</if> <if test="price != null">price = #{price},</if> <if test="description != null">description = #{description},</if> <if test="image != null">image = #{image},</if> <if test="status != null">status = #{status},</if> <if test="updateTime != null">update_time = #{updateTime},</if> <if test="updateUser != null">update_user = #{updateUser},</if> </set> where id = #{id} </update>
5、起售停售套餐 - POST接口
【1】controller层
/** * 起售停售套餐 * @param status * @param id * @return */ @PostMapping("/status/{status}") @ApiOperation("起售停售套餐") public Result startOrStop(@PathVariable Integer status,Long id){ log.info("起售停售套餐:{},{}",status,id); setmealService.startOrStop(status,id); return Result.success(); }【2】service层
/** * 起售停售套餐 * @param status * @param id */ public void startOrStop(Integer status, Long id) { Setmeal setmeal = Setmeal.builder() .status(status) .id(id) .build(); setmealMapper.update(setmeal); }
套餐模块开发结束~撒花!

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐























所有评论(0)