套餐模块功能开发
1. 新增套餐
1.1 需求分析和设计
1.1.1产品原型:
业务规则:
- 套餐名称唯一
- 套餐必须属于某个分类
- 套餐必须包含菜品
- 名称、分类、价格、图片为必填项
- 添加菜品窗口需要根据分类类型来展示菜品
- 新增的套餐默认为停售状态
接口设计(共涉及到4个接口):
- 根据类型查询分类(已完成)
- 根据分类id查询菜品
- 图片上传(已完成)
- 新增套餐
1.1.2接口设计:
1.1.3数据库设计:
setmeal表为套餐表,用于存储套餐的信息。具体表结构如下:
字段名数据类型说明备注idbigint主键自增namevarchar(32)套餐名称唯一category_idbigint分类id逻辑外键pricedecimal(10,2)套餐价格imagevarchar(255)图片路径descriptionvarchar(255)套餐描述statusint售卖状态1起售 0停售create_timedatetime创建时间update_timedatetime最后修改时间create_userbigint创建人idupdate_userbigint最后修改人id
setmeal_dish表为套餐菜品关系表,用于存储套餐和菜品的关联关系。具体表结构如下:
字段名数据类型说明备注idbigint主键自增setmeal_idbigint套餐id逻辑外键dish_idbigint菜品id逻辑外键namevarchar(32)菜品名称冗余字段pricedecimal(10,2)菜品单价冗余字段copiesint菜品份数
1.2 代码开发
1.2.1 DishController层
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/@GetMapping("/list")@ApiOperation("根据分类id查询菜品")publicResult<List<Dish>>list(Long categoryId){List<Dish> list = dishService.list(categoryId);returnResult.success(list);}
1.2.2 DishService接口类
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/List<Dish>list(Long categoryId);
1.2.3 DishServiceImpl接口实现类
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/publicList<Dish>list(Long categoryId){Dish dish =Dish.builder().categoryId(categoryId).status(StatusConstant.ENABLE).build();return dishMapper.list(dish);}
1.2.4 DishMapper层
/**
* 动态条件查询菜品
* @param dish
* @return
*/List<Dish>list(Dish dish);
1.2.5 DishMapper.xml
<selectid="list"resultType="Dish"parameterType="Dish">
select * from dish
<where><iftest="name != null">
and name like concat('%',#{name},'%')
</if><iftest="categoryId != null">
and category_id = #{categoryId}
</if><iftest="status != null">
and status = #{status}
</if></where>
order by create_time desc
</select>
1.2.6 SetmealController层
/**
* 套餐管理
*/@RestController@RequestMapping("/admin/setmeal")@Api(tags ="套餐相关接口")@Slf4jpublicclassSetmealController{@AutowiredprivateSetmealService setmealService;/**
* 新增套餐
* @param setmealDTO
* @return
*/@PostMapping@ApiOperation("新增套餐")publicResultsave(@RequestBodySetmealDTO setmealDTO){
setmealService.saveWithDish(setmealDTO);returnResult.success();}}
1.2.7 SetmealService接口类
publicinterfaceSetmealService{/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @param setmealDTO
*/voidsaveWithDish(SetmealDTO setmealDTO);}
1.2.8 SetmealServiceImpl接口实现类
/**
* 套餐业务实现
*/@Service@Slf4jpublicclassSetmealServiceImplimplementsSetmealService{@AutowiredprivateSetmealMapper setmealMapper;@AutowiredprivateSetmealDishMapper setmealDishMapper;@AutowiredprivateDishMapper dishMapper;/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @param setmealDTO
*/@TransactionalpublicvoidsaveWithDish(SetmealDTO setmealDTO){Setmeal setmeal =newSetmeal();BeanUtils.copyProperties(setmealDTO, setmeal);//向套餐表插入数据
setmealMapper.insert(setmeal);//获取生成的套餐idLong setmealId = setmeal.getId();List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
setmealDishes.forEach(setmealDish ->{
setmealDish.setSetmealId(setmealId);});//保存套餐和菜品的关联关系
setmealDishMapper.insertBatch(setmealDishes);}}
1.2.9 SetmealMapper层
/**
* 新增套餐
* @param setmeal
*/@AutoFill(OperationType.INSERT)voidinsert(Setmeal setmeal);
1.2.10 SetmealMapper.xml
<insertid="insert"parameterType="Setmeal"useGeneratedKeys="true"keyProperty="id">
insert into setmeal
(category_id, name, price, status, description, image, create_time, update_time, create_user, update_user)
values (#{categoryId}, #{name}, #{price}, #{status}, #{description}, #{image}, #{createTime}, #{updateTime},
#{createUser}, #{updateUser})
</insert>
1.2.11 SetmealDishMapper层
/**
* 批量保存套餐和菜品的关联关系
* @param setmealDishes
*/voidinsertBatch(List<SetmealDish> setmealDishes);
1.2.12 SetmealDishMapper.xml
<insertid="insertBatch"parameterType="list">
insert into setmeal_dish
(setmeal_id,dish_id,name,price,copies)
values
<foreachcollection="setmealDishes"item="sd"separator=",">
(#{sd.setmealId},#{sd.dishId},#{sd.name},#{sd.price},#{sd.copies})
</foreach></insert>
2. 套餐分页查询
2.1 需求分析和设计
2.1.1产品原型:
业务规则:
- 根据页码进行分页展示
- 每页展示10条数据
- 可以根据需要,按照套餐名称、分类、售卖状态进行查询
2.1.2接口设计:
2.2 代码开发
2.2.1 SetmealController层
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/@GetMapping("/page")@ApiOperation("分页查询")publicResult<PageResult>page(SetmealPageQueryDTO setmealPageQueryDTO){PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);returnResult.success(pageResult);}
2.2.2 SetmealService接口类
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/PageResultpageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
2.2.3 SetmealServiceImpl接口实现类
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/publicPageResultpageQuery(SetmealPageQueryDTO setmealPageQueryDTO){int pageNum = setmealPageQueryDTO.getPage();int pageSize = setmealPageQueryDTO.getPageSize();PageHelper.startPage(pageNum, pageSize);Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);returnnewPageResult(page.getTotal(), page.getResult());}
2.2.4 SetmealMapper层
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/Page<SetmealVO>pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
2.2.5 SetmealMapper.xml
<selectid="pageQuery"resultType="com.sky.vo.SetmealVO">
select
s.*,c.name categoryName
from
setmeal s
left join
category c
on
s.category_id = c.id
<where><iftest="name != null">
and s.name like concat('%',#{name},'%')
</if><iftest="status != null">
and s.status = #{status}
</if><iftest="categoryId != null">
and s.category_id = #{categoryId}
</if></where>
order by s.create_time desc
</select>
3. 删除套餐
3.1 需求分析和设计
3.1.1产品原型:
业务规则:
- 可以一次删除一个套餐,也可以批量删除套餐
- 起售中的套餐不能删除
3.1.2接口设计:
3.2 代码实现
3.2.1 SetmealController层
/**
* 批量删除套餐
* @param ids
* @return
*/@DeleteMapping@ApiOperation("批量删除套餐")publicResultdelete(@RequestParamList<Long> ids){
setmealService.deleteBatch(ids);returnResult.success();}
3.2.2 SetmealService接口类
/**
* 批量删除套餐
* @param ids
*/voiddeleteBatch(List<Long> ids);
3.2.3 SetmealServiceImpl接口实现类
/**
* 批量删除套餐
* @param ids
*/@TransactionalpublicvoiddeleteBatch(List<Long> ids){
ids.forEach(id ->{Setmeal setmeal = setmealMapper.getById(id);if(StatusConstant.ENABLE== setmeal.getStatus()){//起售中的套餐不能删除thrownewDeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);}});
ids.forEach(setmealId ->{//删除套餐表中的数据
setmealMapper.deleteById(setmealId);//删除套餐菜品关系表中的数据
setmealDishMapper.deleteBySetmealId(setmealId);});}
3.2.4 SetmealMapper层
/**
* 根据id查询套餐
* @param id
* @return
*/@Select("select * from setmeal where id = #{id}")SetmealgetById(Long id);/**
* 根据id删除套餐
* @param setmealId
*/@Delete("delete from setmeal where id = #{id}")voiddeleteById(Long setmealId);
3.2.5 SetmealDishMapper
/**
* 根据套餐id删除套餐和菜品的关联关系
* @param setmealId
*/@Delete("delete from setmeal_dish where setmeal_id = #{setmealId}")voiddeleteBySetmealId(Long setmealId);
4. 修改套餐
4.1 需求分析和设计
4.1.1产品原型:
4.1.2接口设计(共涉及到5个接口):
- 根据id查询套餐
- 根据类型查询分类(已完成)
- 根据分类id查询菜品(已完成)
- 图片上传(已完成)
- 修改套餐
4.2 代码实现
4.2.1 SetmealController层
/**
* 根据id查询套餐,用于修改页面回显数据
*
* @param id
* @return
*/@GetMapping("/{id}")@ApiOperation("根据id查询套餐")publicResult<SetmealVO>getById(@PathVariableLong id){SetmealVO setmealVO = setmealService.getByIdWithDish(id);returnResult.success(setmealVO);}/**
* 修改套餐
*
* @param setmealDTO
* @return
*/@PutMapping@ApiOperation("修改套餐")publicResultupdate(@RequestBodySetmealDTO setmealDTO){
setmealService.update(setmealDTO);returnResult.success();}
4.2.2 SetmealService接口类
/**
* 根据id查询套餐和关联的菜品数据
* @param id
* @return
*/SetmealVOgetByIdWithDish(Long id);/**
* 修改套餐
* @param setmealDTO
*/voidupdate(SetmealDTO setmealDTO);
4.2.3 SetmealServiceImpl接口实现类
/**
* 根据id查询套餐和套餐菜品关系
*
* @param id
* @return
*/publicSetmealVOgetByIdWithDish(Long id){Setmeal setmeal = setmealMapper.getById(id);List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);SetmealVO setmealVO =newSetmealVO();BeanUtils.copyProperties(setmeal, setmealVO);
setmealVO.setSetmealDishes(setmealDishes);return setmealVO;}/**
* 修改套餐
*
* @param setmealDTO
*/@Transactionalpublicvoidupdate(SetmealDTO setmealDTO){Setmeal setmeal =newSetmeal();BeanUtils.copyProperties(setmealDTO, setmeal);//1、修改套餐表,执行update
setmealMapper.update(setmeal);//套餐idLong 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);}
4.2.4 SetmealDishMapper层
/**
* 根据套餐id查询套餐和菜品的关联关系
* @param setmealId
* @return
*/@Select("select * from setmeal_dish where setmeal_id = #{setmealId}")List<SetmealDish>getBySetmealId(Long setmealId);
5. 起售停售套餐
5.1 需求分析和设计
5.1.1产品原型:
业务规则:
- 可以对状态为起售的套餐进行停售操作,可以对状态为停售的套餐进行起售操作
- 起售的套餐可以展示在用户端,停售的套餐不能展示在用户端
- 起售套餐时,如果套餐内包含停售的菜品,则不能起售
5.1.2接口设计:
5.2 代码实现
5.2.1 SetmealController层
/**
* 套餐起售停售
* @param status
* @param id
* @return
*/@PostMapping("/status/{status}")@ApiOperation("套餐起售停售")publicResultstartOrStop(@PathVariableInteger status,Long id){
setmealService.startOrStop(status, id);returnResult.success();}
5.2.2 SetmealService接口类
/**
* 套餐起售、停售
* @param status
* @param id
*/voidstartOrStop(Integer status,Long id);
5.2.3 SetmealServiceImpl接口实现类
/**
* 套餐起售、停售
* @param status
* @param id
*/publicvoidstartOrStop(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()){thrownewSetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);}});}}Setmeal setmeal =Setmeal.builder().id(id).status(status).build();
setmealMapper.update(setmeal);}
5.2.4 DishMapper层
/**
* 根据套餐id查询菜品
* @param setmealId
* @return
*/@Select("select a.* from dish a left join setmeal_dish b on a.id = b.dish_id where b.setmeal_id = #{setmealId}")List<Dish>getBySetmealId(Long setmealId);
后记
👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹
版权归原作者 失重外太空. 所有, 如有侵权,请联系我们删除。