一.删除菜品
在前面我们分析了删除菜品的业务逻辑,其中前端传递过来的参数是一个字符串类型的参数。比如要删除id为1,2,3的菜品,那么前端传递过来的参数就是?1,2,3。这种参数类型如果接收的话我们应该使用@RequestParam,因为我们要将其传递过来的参数封装到一个List集合当中,因此我们使用@RequestParam。这样Spring MVC 会映射以逗号分割的参数,然后将其填入List集合中。
此外,在删除菜品时也要注意,以下情况是必须要考虑的。

二.Controller层
package com.sky.controller.admin;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
@Autowired
private DishService dishService;
/**
* 新增菜品
* @param dishDTO
* @return
*/
@PostMapping
@ApiOperation("新增菜品")
public Result save(@RequestBody DishDTO dishDTO) { // 前端传递过来的Json格式的数据,要使用@RequestBody注解修饰变量来接收
log.info("新增菜品:{}",dishDTO);
dishService.saveWithFlavor(dishDTO);
return Result.success();
}
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("菜品分页查询")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
log.info("菜品分页查询:{}",dishPageQueryDTO);
PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
/**
* 批量删除菜品
* @param ids
* @return
*/
@DeleteMapping
@ApiOperation("批量删除菜品")
public Result deleteBatch(@RequestParam List<Long> ids) {
log.info("批量删除菜品:{}",ids);
dishService.deleteByIds(ids);
return Result.success();
}
}
三.Service层
接口
package com.sky.service;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.result.PageResult;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public interface DishService {
/**
* 新增菜品
* @param dishDTO
*/
void saveWithFlavor(DishDTO dishDTO);
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO);
/**
* 批量删除菜品
* @param ids
*/
void deleteByIds(List<Long> ids);
}
实现类
package com.sky.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.constant.StatusConstant;
import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.entity.DishFlavor;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.DishFlavorMapper;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealDishMapper;
import com.sky.result.PageResult;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.function.Consumer;
@Service
public class DishServiceImpl implements DishService {
@Autowired
private DishMapper dishMapper;
@Autowired
private DishFlavorMapper dishFlavorMapper;
@Autowired
private SetmealDishMapper setmealDishMapper;
/**
* 新增菜品
* @param dishDTO
*/
@Transactional // 要对dish表和dish_flavor表同时进行操作,因此要使用事务,这两个操作要么同时成功,要么同时失败
@Override
public void saveWithFlavor(DishDTO dishDTO) {
// 我们要往dish表里写入数据,因此要创建一个Dish对象,将该Dish对象插入表中
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO,dish);
// 向dish表插入1条数据
dishMapper.insert(dish);
List<DishFlavor> flavors = dishDTO.getFlavors();
if (flavors != null && flavors.size() > 0) {
// 注意:我们在dish_flavor往里插入数据的时候,需要拿到当前dish的id,才能插入到dish_flavor中的dishId字段
Long dishId = dish.getId(); // 直接这样获取是获取不到的,因为默认情况下,执行基础的insert操作,是不会把主键值返回的。即使在数据库中已为其分配了主键id,但是直接get是无法拿到的,这时候就要使用主键返回功能 https://www.bilibili.com/video/BV1m84y1w7Tb?spm_id_from=333.788.videopod.episodes&vd_source=29b615752ffbc51f0ac76a344682247a&p=126
flavors.forEach(dishFlavor -> {
dishFlavor.setDishId(dishId); // lambda表达式,遍历flavor集合并为其中的dishId属性赋值
});
// 向口味表插入n条数据
dishFlavorMapper.insertBatch(flavors); // 批量插入
}
}
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
// 执行PageHelper插件
PageHelper.startPage(dishPageQueryDTO.getPage(),dishPageQueryDTO.getPageSize());
// 执行Mapper层进行查询
Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
return new PageResult(page.getTotal(),page.getResult());
}
/**
* 批量删除菜品
* @param ids
*/
@Transactional
@Override
public void deleteByIds(List<Long> ids) {
// 1.首先判断该菜品状态,有启售售状态菜品则该次删除操作失败
for (Long id : ids) {
Dish dish = dishMapper.getById(id); // 根据id查询对应菜品
Integer status = dish.getStatus();
if (status == StatusConstant.ENABLE)
throw new DeletionNotAllowedException(MessageConstant.DISH_ON_SALE);
}
// 2.接着判断该菜品是否有关联的套餐,有关联套餐的菜品则该次删除操作失败————查询setmeal_dish表
List<Long> setmealIds = setmealDishMapper.getSetmealIdsByDishIds(ids);
if (setmealIds != null && setmealIds.size() > 0) {
throw new DeletionNotAllowedException(MessageConstant.DISH_BE_RELATED_BY_SETMEAL);
}
// // 3.批量删除菜品
// for (Long id : ids) {
// dishMapper.deleteByIds(id); // 之所以不用动态批量删除,是因为还要删除dish_id对应的口味,因此直接查一删一方便
// // 4.删除菜品关联的口味
// dishFlavorMapper.deleteByDishId(id);
// }
// 虽然使用for循环一一删除逻辑上简单,但是使用for循环每次调用两个mapper接口,性能影响大,因此使用批量删除
dishMapper.deleteByIds(ids); // 批量删除菜品
dishFlavorMapper.deleteByDishIds(ids); // 批量删除口味
}
}
1.首先判断该菜品状态,有启售售状态菜品则该次删除操作失败。因此要根据id进行菜品的查询并判断菜品status,如果status等于1,那么就抛出菜品启售异常。
2.接着判断该菜品是否有关联的套餐,有关联套餐的菜品则该次删除操作失败————查询setmeal_dish表。我们通过查询该菜品关联的套餐来确定时候该菜品有套餐关联,如果有就不允许删除。因此我们使用SQL语句:
select setmeal_id from setmeal_dish where dish_id in ids;
使用集合接收查询到的套餐id。如果该集合不为空且该集合中的元素个数大于零,那么就证明这些菜品与套餐有关联,那么就抛出菜品关联套餐异常,不允许删除。
3.如果当前要删除的菜品既没有启售的,又没有与套餐相关联的,那么就允许删除。我们会删菜品以及其关联的口味,因此要操作两个表:dish,dish_flavor表。我们要让这两个表要么同时删除成功,要门同时删除失败,因此在方法上加上@Transactional注解表示该方法下的操作是一个事务。
我们调用deleteByIds(ids)批量删除菜品,调用deleteByDishIds(ids)批量删除口味。
四.Mapper层
DishMapper.class
package com.sky.mapper;
import com.github.pagehelper.Page;
import com.sky.annotation.AutoFill;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.enumeration.OperationType;
import com.sky.vo.DishVO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface DishMapper {
/**
* 根据category_id查询菜品中的该分类数
* @param categoryId
* @return
*/
@Select("select count(*) from dish where category_id = #{categoryId}")
Integer countByCategoryId(Long categoryId);
/**
* 新增菜品
* @param dish
*/
@AutoFill(value = OperationType.INSERT)
void insert(Dish dish);
/**
* 菜品分页查询
* @param dishPageQueryDTO
* @return
*/
Page<DishVO> pageQuery(DishPageQueryDTO dishPageQueryDTO);
/**
* 根据id查询菜品
* @param id
* @return
*/
@Select("select * from dish where id = #{id}")
Dish getById(Long id);
/**
* 删除菜品
* @param id
*/
@Delete("delete from dish where id = #{id}")
void deleteById(Long id);
/**
* 批量删除菜品
* @param ids
*/
void deleteByIds(List<Long> ids);
}
SetmealDishMapper.class
package com.sky.mapper;
import com.sky.entity.SetmealDish;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface SetmealDishMapper {
/**
* 根据菜品id查询所在套餐id
* @param ids
* @return
*/
List<Long> getSetmealIdsByDishIds(List<Long> ids);
}
DishFlavorMapper.class
package com.sky.mapper;
import com.sky.entity.DishFlavor;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface DishFlavorMapper {
/**
* 新增口味
* @param dishFlavors
*/
void insertBatch(List<DishFlavor> dishFlavors); // 要进行批量添加,将集合中的元素都添加进去,因此要使用<foreach>
/**
* 根据菜品id删除对应口味
* @param dishId
*/
@Delete("delete from dish_flavor where dish_id = #{dishId}")
void deleteByDishId(Long dishId);
/**
* 根据菜品id批量删除对应口味
* @param dishIds
*/
void deleteByDishIds(List<Long> dishIds);
}
DishMapper.XML
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into dish(name, category_id, price, image, description, status, create_time, update_time, create_user, update_user)
VALUES
(#{name},#{categoryId},#{price},#{image},#{description},#{status},#{createTime},#{updateTime},#{createUser},#{updateUser})
</insert>
<delete id="deleteByIds">
delete from dish where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
<select id="pageQuery" resultType="com.sky.vo.DishVO">
select d.*,c.name as categoryName from dish d left outer join category c on d.category_id = c.id
<where>
<if test="name != null and name !=''">
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 create_time desc
</select>
</mapper>
SetmealDishMapper.XML
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.SetmealDishMapper">
<select id="getSetmealIdsByDishIds" resultType="java.lang.Long">
select setmeal_id from setmeal_dish where dish_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</select>
</mapper>
DishFlavorMapper.class
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.DishFlavorMapper">
<insert id="insertBatch">
insert into dish_flavor(dish_id, name, value) VALUES
<foreach collection="dishFlavors" item="dishFlavor" separator=",">
(#{dishFlavor.dishId}, #{dishFlavor.name}, #{dishFlavor.value})
</foreach>
</insert>
<delete id="deleteByDishIds">
delete from dish_flavor where dish_id in
<foreach collection="dishIds" item="dishId" separator="," open="(" close=")">
#{dishId}
</foreach>
</delete>
</mapper>