Day04 新增套餐
###今天的任务主要是自主完成套餐管理的模块###
1.新增套餐
在前端页面接口中我们可以看到在新增套餐的时候需要选择添加到菜单中的菜品
因此我们需要设计一个接口可以通过根据分类id(category_id)来查询该分类下的菜品
1.1根据分类id查询分类下的菜品
1.DishController
@GetMapping("/list")@ApiOperation("根据分类id查询菜品")public Result<List<Dish>> list(Long categoryId){List<Dish> list = dishService.list(categoryId);return Result.success(list);}
2.dishService
/*** 根据套餐id查询菜品* @param categoryId* @return*/List<Dish> list(Long categoryId);
3.DishServiceImpl
这里需要注意一下,在前端页面中,添加套餐中的菜品可以通过多种的方式搜索:可以直接在展示框中点击(这个就是直接根据id搜索然后回显就好了)、可以通过名字搜索来进行添加(这个就要添加姓名的条件了)。为了方便去进行比较,这里使用对象生成器生成了一个对象,并且对对象进行初始化赋值,这样子就可以更方便的比对。
/*** 根据分类id查询菜品* @param categoryId* @return*/public List<Dish> list(Long categoryId) {Dish dish = Dish.builder().categoryId(categoryId).status(StatusConstant.ENABLE).build();return dishMapper.list(dish);}
4.DishMapper
这里有多种对比方式,所以肯定选择的是动态的SQL
<select id="list" resultType="Dish" parameterType="Dish">select * from 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>
1.2新增菜品
我们已经完成了菜品的回显,现在就可以新增菜品了。
1.2.1SetMealController
这里需要注意一下,前端传回来的数据格式,选择合适的dto进行数据的接收。
/*** 套餐管理*/
@RestController
@RequestMapping("/admin/setmeal")
@Api(tags = "套餐相关接口")
@Slf4j
public class SetmealController {@Autowiredprivate SetmealService setmealService;/*** 新增套餐* @param setmealDTO* @return*/@PostMapping@ApiOperation("新增套餐")public Result save(@RequestBody SetmealDTO setmealDTO) {setmealService.saveWithDish(setmealDTO);return Result.success();}
}
1.2.2SetMealServiceImpl
再新增套餐这个业务中,我们需要对两张表个进行操作:套餐表、套餐-菜品表(因为是多对多的关系,所以通过建立第三个表格来关联)
@Service
@Slf4j
public class SetmealServiceImpl implements SetmealService {@Autowiredprivate SetmealMapper setmealMapper;@Autowiredprivate SetmealDishMapper setmealDishMapper;@Autowiredprivate DishMapper dishMapper;/*** 新增套餐,同时需要保存套餐和菜品的关联关系* @param setmealDTO*/@Transactionalpublic void saveWithDish(SetmealDTO setmealDTO) {Setmeal setmeal = new Setmeal();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);}
}
首先使用了BeanUtils工具对对象属性进行复制提取出了setmeal的信息方便对seatmeal表格进行操作
然后获取setmeal中的套餐id(这里的套餐id用来作为连接表的逻辑链接)
使用DTO中的get方法获得所添加的Dishes然后对其中的每一个对象的mealId进行赋值
最后将Dishes插入到表格中
最终完成了套餐的新增。
2.套餐分页查询
套餐分页查询
产品原型:
2.1Controller方法
对于分页查询,我们使用的是pagehelper这个工具类。该工具类可以帮助我们在动态的SQL语句中插入页面数据。(就比如我们正常编写分页查询的SQL语句的时候会有limit这个来限定每页展示的数量,使用了工具类之后他可以帮我们自动添加上去,不需要在编写这个限定)
@GetMapping("/page")
@ApiOperation("分页查询")
public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO) {PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);return Result.success(pageResult);
}
注意:这里使用了pageresult作为返回的变量,因此在方法类型使用了泛型!!!
2.2ServiceImpl方法
前端传过来的页面数量和每页展示记录数通过get方法获取后需要传入到pagehelper的startpage中(可以理解成这样子就可以自动帮我们将页面数量和每页展示记录数据自动映射)
完成之后我们还需要编写基础的SQL语句来对所展示的记录进行返回
public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {int pageNum = setmealPageQueryDTO.getPage();int pageSize = setmealPageQueryDTO.getPageSize();PageHelper.startPage(pageNum, pageSize);Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());
}
2.3Mapper方法
Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
2.4Xml
为什么要进行两表联查呢?
首先通过category表中的id字段来链接setmeal表中的vategory_id字段
在分页查找中我们可以通过多种方式来进行查找

因此需要有三个条件判断
<select id="pageQuery" resultType="com.sky.vo.SetmealVO">selects.*,c.name categoryNamefromsetmeal sleft joincategory cons.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.删除套餐
1.controller
前端给我们传递了一个id集合,里面包含了要删除的套餐的id(可能没有,可能有一个,可能有多个)
@DeleteMapping
@ApiOperation("批量删除套餐")
public Result delete(@RequestParam List<Long> ids){setmealService.deleteBatch(ids);return Result.success();
}
2.serviceimpl
在service层面当我们处理这个id列表的时候,需要注意:
1.起售中的套餐不能删除(判断每一个id对应的setmeal对象中的status属性)
2.删除的时候需要删除菜单表的数据,也需要删除关联表中的数据(添加事务)3.
@Transactional
public void deleteBatch(List<Long> ids) {ids.forEach(id -> {Setmeal setmeal = setmealMapper.getById(id);if(StatusConstant.ENABLE == setmeal.getStatus()){//起售中的套餐不能删除throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);}});ids.forEach(setmealId -> {//删除套餐表中的数据setmealMapper.deleteById(setmealId);//删除套餐菜品关系表中的数据setmealDishMapper.deleteBySetmealId(setmealId);});
}
3.Mapper
编写的SQL语句比较简单就不过多展示。
4. 修改套餐
对于修改操作,我们都需要对数据进行回显
4.1根据id查询套餐
@GetMapping("/{id}")
@ApiOperation("根据id查询套餐")
public Result<SetmealVO> getById(@PathVariable Long id) {SetmealVO setmealVO = setmealService.getByIdWithDish(id);return Result.success(setmealVO);//service
public SetmealVO getByIdWithDish(Long id) {Setmeal setmeal = setmealMapper.getById(id);List<SetmealDish> setmealDishes = setmealDishMapper.getBySetmealId(id);SetmealVO setmealVO = new SetmealVO();BeanUtils.copyProperties(setmeal, setmealVO);setmealVO.setSetmealDishes(setmealDishes);return setmealVO;
}//mapper@Select("select * from setmeal_dish where setmeal_id = #{setmealId}")List<SetmealDish> getBySetmealId(Long setmealId);
注意:这里使用了两个get方法来获取数据!!!
因为这里需要对数据进行一个回显,所以选择了VO格式的对象对数据进行封装。
4.2更新数据
//Controller
@PutMapping
@ApiOperation("修改套餐")
public Result update(@RequestBody SetmealDTO setmealDTO) {setmealService.update(setmealDTO);return Result.success();
}@Transactional
public void update(SetmealDTO setmealDTO) {Setmeal setmeal = new Setmeal();BeanUtils.copyProperties(setmealDTO, setmeal);//1、修改套餐表,执行updatesetmealMapper.update(setmeal);//套餐idLong setmealId = setmealDTO.getId();//2、删除套餐和菜品的关联关系,操作setmeal_dish表,执行deletesetmealDishMapper.deleteBySetmealId(setmealId);List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();setmealDishes.forEach(setmealDish -> {setmealDish.setSetmealId(setmealId);});//3、重新插入套餐和菜品的关联关系,操作setmeal_dish表,执行insertsetmealDishMapper.insertBatch(setmealDishes);
}
其实这里的操作和插入数据有类似的:
对setmeal套餐表中的数据进行更新
获取更新过后套餐的id
删除套餐和菜品之间的关系(根据套餐的id)
重新插入套餐和菜品之间的关系
5.起售停售套餐
这个功能比较简单,主要是注意起售菜品的时候需要判断套餐中是否有停售菜品
//Controller
@PostMapping("/status/{status}")
@ApiOperation("套餐起售停售")
public Result startOrStop(@PathVariable Integer status, Long id) {setmealService.startOrStop(status, id);return Result.success();
}//Service
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
@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);