文章目录
前言
此部分主要包括菜品分页查询,批量删除菜品以及修改菜品。本质上都是一些增删改查,只是要分析清楚业务规则,不同于员工操作,菜品可能关联了口味或者套餐,通常就涉及多表操作。例如:在删除菜品的时候,也要把对应的口味表中信息删除,而起售中的菜品、被套餐关联的菜品不能删除 ;在修改菜品的时候,可能也要修改相应的口味表中的信息…
一、菜品分页查询
菜品信息分页展示在前端界面中
1、接口设计
根据接口定义设计对应的DTO
根据接口定义设计对应的VO
2、代码开发
1、DishController定义page分页查询方法
@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO){
log.info("菜品分页查询:{}",dishPageQueryDTO);
PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
2、在DishService接口扩展分页查询方法,在 DishServiceImpl 中实现方法
@Override
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
return new PageResult(page.getTotal(), page.getResult());
}
3、在 DishMapper 接口中声明 pageQuery 方法,并在在 DishMapper.xml 中编写SQL语句(多表联查)
<select id="pageQuery" resultType="com.sky.vo.DishVO">
<!--因为dish表中和category表中都有name属性,要为其中一个表中的name取别名-->
select d.*,c.`name` as categoryName from sky_take_out.dish d left outer JOIN sky_take_out.category c on
d.category_id = c.id
<where>
<if test="name != null"> and d.name like CONCAT('%',#{name},'%') </if>
<if test="categoryId != null"> and d.category_id = #{categoryId} </if>
<if test="status != null"> and d.status = #{status} </if>
</where>
order by d.create_time desc
</select>
二、删除菜品
1、业务规则
- 可以一次删除一个菜品,也可以批量删除菜品
- 起售中的菜品不能删除
- 被套餐关联的菜品不能删除
- 删除菜品后,关联的口味数据也需要删除掉
2、接口设计
3、数据库设计
根据业务规则可知,这里关联了三张表格。
4、代码开发
1、根据删除菜品的接口定义在DishController中创建方法
@DeleteMapping
@ApiOperation("菜品批量删除")
public Result delete(@RequestParam List<Long> ids){
log.info("菜品批量删除:{}",ids);
dishService.deleteBatch(ids);
return Result.success();
}
2、在DishService接口中声明deleteBatch方法,在DishServiceImpl中实现deleteBatch方法
@Transactional //涉及多表操作,开启事务管理,确保方法的原子性
public void deleteBatch(List<Long> ids) {
//1、判断当前菜品是否能够删除--是否存在起售中的菜品 status
for (Long id : ids) {
//根据菜品id查询这个菜品所有信息,返回一个dish对象
Dish dish = dishMapper.getById(id);
if(dish.getStatus() == StatusConstant.ENABLE){
//当前菜品处于起售中,不能删除
throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
}
}
//2、判断当前菜品是否能够删除--根据菜品id查询是否被套餐关联了
List<Long> setmealIds = setmealDishMapper.getSetmealIdByDishIds(ids);
if(setmealIds != null && setmealIds.size() > 0){
//当前菜品被套餐关联,不能删除
throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
}
//3、删除菜品表中的菜品数据
/* for (Long id : ids) {
dishMapper.deleteById(id);
//删除菜品关联的口味数据
dishFlavorMapper.deleteByDishId(id);
} */
//批量删除
//delete from dish where id in {?,?,?}
//根据菜品id集合批量删除菜品数据
dishMapper.deleteByIds(ids);
//delete from dish_flavor where id in {?,?,?}
//根据菜品id集合批量删除关联的口味数据
dishFlavorMapper.deleteByDishIds(ids);
}
3、在DishMapper中声明getById方法,并配置Sql语句
@Select("select * from sky_take_out.dish where id = #{id}")
Dish getById(Long id);
4、在SetmealDishMapper声明getSetmealIdsByDishIds方法,并在SetmealDishMapper.xml文件中编写SQL
<select id="getSetmealIdByDishIds" resultType="java.lang.Long">
select setmeal_id from sky_take_out.setmeal_dish where dish_id in
<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">
#{dishId}
</foreach>
</select>
5、在DishMapper.xml中声明deleteById方法并配置SQL
@Delete("delete from dish where id = #{id}")
void deleteById(Long id);
6、在DishFlavorMapper中声明deleteByDishId方法并配置SQL
@Delete("delete from dish_flavor where dish_id = #{dishId}")
void deleteByDishId(Long dishId);
三、修改菜品
1、接口设计
- 根据id查询菜品 (菜品信息回显)
- 根据菜品类型查询分类(已实现)
- 文件上传(已实现)
- 修改菜品
1.1 根据id查询菜品
1.2 修改菜品
2、代码开发
2.1 根据id查询菜品
查询的信息包括菜品信息和关联的口味数据
1、在Dishcontroller中编写方法
@GetMapping("/{id}")
@ApiOperation("根据id查询菜品")
public Result<DishVO> getById(@PathVariable Long id){
log.info("根据id查询菜品 {}",id);
DishVO dishVO = dishService.getByIdWithFlavor(id);
return Result.success(dishVO);
}
2、在DishService接口中定义getByIdWithFlavor方法,在DishServiceImpl中实现方法
public DishVO getByIdWithFlavor(Long id) {
//先根据id查询菜品数据
Dish dish = dishMapper.getById(id);
//根据菜品id查询关联的口味
List<DishFlavor> dishFlavors = dishFlavorMapper.getByDishId(id);
//将查询到的数据封装到VO
DishVO dishVO = new DishVO();
BeanUtils.copyProperties(dish,dishVO);
dishVO.setFlavors(dishFlavors);
return dishVO;
}
3、分别在DishMapper定义getById方法(菜品分页查询业务中已定义)和DishFlavorMapper接口中定义getByDishId方法
@Select("select * from sky_take_out.dish_flavor where dish_id = #{dishId}")
List<DishFlavor> getByDishId(Long dishId);
2.2 修改菜品
1、在Dishcontroller中编写方法
@PutMapping
@ApiOperation("修改菜品")
public Result update(@RequestBody DishDTO dishDTO){
log.info("修改菜品 {}",dishDTO);
dishService.updateWithFlavor(dishDTO);
return Result.success();
}
2、在DishService接口中定义gupdateWithFlavor方法,在DishServiceImpl中实现方法
public void updateWithFlavor(DishDTO dishDTO) {
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO,dish);
//1 修改菜品表基本信息
dishMapper.update(dish);
//2 先删除原来的口味数据
dishFlavorMapper.deleteByDishId(dishDTO.getId());
//3 再插入口味
List<DishFlavor> flavors = dishDTO.getFlavors();
if(flavors != null && flavors.size() > 0){
flavors.forEach(dishFlavor -> {
dishFlavor.setDishId(dishDTO.getId());
});
//向口味表插入n条数据
dishFlavorMapper.insertBatch(flavors);
}
}
3、在dishMapper中定义方法
@AutoFill(OperationType.UPDATE)
void update(Dish dish);
4、在dishMapper.xml中编写sql语句
<update id="update">
update sky_take_out.dish
<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="image != null">image = #{image},</if>
<if test="description != null">description = #{description},</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>
四、菜品起售停售
1、接口设计
菜品起售表示该菜品可以对外售卖,在用户端可以点餐
菜品停售表示此菜品下架,用户端无法点餐
如果执行停售操作,则包含此菜品的套餐也需要停售。(一定要注意这一点)
2、代码开发
1、在dishController层编写方法
@PostMapping("/status/{status}")
@ApiOperation("菜品起售停售")
public Result startOrStop(@PathVariable Integer status,Long id){
log.info("菜品起售停售:{},{}",status,id);
dishService.startOrStop(status,id);
return Result.success();
}
2、在DishService接口编写方法,在DishServiceImpl类中实现
//update employee set status = ? where id = ?
public void startOrStop(Integer status, Long id) {
Dish dish = Dish.builder()
.status(status)
.id(id)
.build();
dishMapper.update(dish);
//如果是停售操作,那么菜品所关联的套餐也不能售卖
if(status == StatusConstant.DISABLE){
ArrayList<Long> dishIds = new ArrayList<>();
dishIds.add(id);
// select setmealId from setmeal_dish where dish_id in (?,?,?)
List<Long> setmealIds = setmealDishMapper.getSetmealIdByDishIds(dishIds);
if(setmealIds != null &&setmealIds.size()>0){
for (Long setmealId :setmealIds) {
Setmeal setmeal = Setmeal.builder()
.id(setmealId)
.status(StatusConstant.DISABLE)
.build();
setmealMapper.update(setmeal);
}
}
}
}
3、调用DishMapper中的update方法(修改菜品中已实现),对菜品内容进行修改,根据id修改status。
4、在SetmealMapper中定义update方法,对改菜品相关联的套餐信息就行修改,然后再SetmealMapper.xml中编写sql语句。
@AutoFill(OperationType.UPDATE)
void update(Setmeal setmeal);
<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="image != null">image = #{image},</if>
<if test="description != null">description = #{description},</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>