1. 新增套餐
1 需求分析和设计
业务规则:
套餐名称唯一
套餐必须属于某个分类
套餐必须包含菜品
名称、分类、价格、图片为必填项
添加菜品窗口需要根据分类类型来展示菜品
新增的套餐默认为停售状态
2 代码实现
1 根据分类id查询菜品
DishController
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品列表")
public Result queryDishesByCategoryId(Long categoryId){
return dishService.queryDishesByCategoryId(categoryId);
}
----------------
DishService
/**
* 根据分类id查询菜品列表
* @param categoryId 分类id
* @return categoryId对应的菜品列表
*/
Result queryDishesByCategoryId(Long categoryId);
----------------
DishServiceImpl
@Override
public Result queryDishesByCategoryId(Long categoryId) {
List<Dish> dishes = dishMapper.selectByCategoryId(categoryId);
return Result.success(dishes);
}
----------------
DishMapper
@Select("select * from dish where category_id = #{categoryId}")
List<Dish> selectByCategoryId(Long categoryId);
2 新增套餐
SetmealController
package com.sky.controller.admin;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@Api(tags = "套餐管理相关接口")
@RequestMapping("/admin/setmeal")
public class SetmealController {
@Autowired
private SetmealService setmealService;
@PostMapping
@ApiOperation("新增套餐")
public Result addSetmeal(@RequestBody SetmealDTO dto){
return setmealService.addSetmeal(dto);
}
}
-----------------
SetmealService
package com.sky.service;
import com.sky.dto.SetmealDTO;
import com.sky.result.Result;
import java.util.List;
public interface SetmealService {
Result addSetmeal(SetmealDTO dto);
}
-----------------
SetmealServiceImpl
package com.sky.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.entity.Setmeal;
import com.sky.entity.SetmealDish;
import com.sky.exception.DeletionNotAllowedException;
import com.sky.mapper.SetmealMapper;
import com.sky.mapper.SetmeatlDishMapper;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import com.sky.vo.SetmealVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class SetmealServiceImpl implements SetmealService {
@Autowired
private SetmealMapper setmealMapper;
@Autowired
private SetmeatlDishMapper setmealDishMapper;
@Override
@Transactional
public Result addSetmeal(SetmealDTO dto) {
//1. 保存套餐
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(dto, setmeal);
setmealMapper.insert(setmeal);
//2. 保存套餐里关联的菜品
List<SetmealDish> setmealDishes = dto.getSetmealDishes();
if (setmealDishes != null && setmealDishes.size() > 0) {
setmealDishes.forEach(setmealDish -> setmealDish.setSetmealId(setmeal.getId()));
setmealDishMapper.batchInsert(setmealDishes);
}
return Result.success();
}
}
-----------------
SetmealMapper
/**
* 新增套餐
* @param setmeal
*/
@AutoFill(OperationType.INSERT)
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("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})")
void insert(Setmeal setmeal);
-------------------
SetmeatlDishMapper
void batchInsert(List<SetmealDish> setmealDishes);
----------------
SetmeatlDishMapper.xml
<insert id="batchInsert">
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. 套餐分页查询
1 需求分析和设计
业务规则:
根据页码进行分页展示
每页展示10条数据
可以根据需要,按照套餐名称、分类、售卖状态进行查询
2 代码实现
SetmealController
@GetMapping("/page")
@ApiOperation("分页查询套餐")
public Result querySetmealsByPage(SetmealPageQueryDTO dto){
return setmealService.querySetmealsByPage(dto);
}
----------------
SetmealService
/**
* 分页查询套餐
* @param dto
* @return
*/
Result querySetmealsByPage(SetmealPageQueryDTO dto);
----------------
SetmealServiceImpl
@Override
public Result querySetmealsByPage(SetmealPageQueryDTO dto) {
//1. 开启分页
PageHelper.startPage(dto.getPage(), dto.getPageSize());
//2. 查询列表
Page<SetmealVO> page = setmealMapper.selectByPage(dto);
//3. 封装结果
PageResult pageResult = new PageResult(page.getTotal(), page.getResult());
return Result.success(pageResult);
}
--------------
SetmealMapper
/**
* 分页查询套餐列表
* @param dto
* @return
*/
Page<SetmealVO> selectByPage(SetmealPageQueryDTO dto);
--------------
SetmealMapper.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.SetmealMapper">
<select id="selectByPage" resultType="com.sky.vo.SetmealVO">
select s.*, c.name categoryName from setmeal s left join category c on s.category_id = c.id
<where>
<if test="name!=null and name.length()>0">
and s.name like concat('%', #{name}, '%')
</if>
<if test="categoryId!=null">
and s.category_id = #{categoryId}
</if>
<if test="status!=null">
and s.status = #{status}
</if>
</where>
order by s.create_time desc
</select>
</mapper>
3. 删除套餐
1 需求分析和设计
业务规则:
可以一次删除一个套餐,也可以批量删除套餐
起售中的套餐不能删除
2 代码实现
SetmealController
@DeleteMapping
@ApiOperation("删除套餐")
public Result batchDeleteSetmealsByIds(@RequestParam List<Long> ids){
return setmealService.batchDeleteSetmealsByIds(ids);
}
----------
SetmealService
/**
* 批量删除套餐
* @param ids
*/
Result batchDeleteSetmealsByIds(List<Long> ids);
----------
SetmealServiceImpl
@Override
@Transactional
public Result batchDeleteSetmealsByIds(List<Long> ids) {
//1. 如果有某个套餐是“起售”状态,则不允许删除
int count = setmealMapper.selectEnableSetmealsCount(ids);
if (count > 0) {
throw new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);
}
//2. 删除套餐
setmealMapper.batchDeleteByIds(ids);
//3. 删除套餐关联的菜品
setmealDishMapper.batchDeleteBySetmealIds(ids);
return Result.success();
}
-----------
SetmealMapper
/**
* 查询 ids对应的套餐中,起售状态的套餐 数量
* @param ids
* @return
*/
int selectEnableSetmealsCount(List<Long> ids);
/**
* 根据ids批量删除套餐
* @param ids
*/
void batchDeleteByIds(List<Long> ids);
------------
SetmealMapper.xml
<select id="selectEnableSetmealsCount" resultType="int">
select count(*) from setmeal where status = 1 and
<foreach collection="ids" item="id" separator="," open="id in(" close=")">
#{id}
</foreach>
</select>
<delete id="batchDeleteByIds">
delete from setmeal where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
---------------
SetmeatlDishMapper
/**
* 根据套餐ids,批量删除这些套餐包含的菜品关联关系
* @param ids
*/
void batchDeleteBySetmealIds(List<Long> ids);
-----------
SetmeatlDishMapper.xml
<delete id="batchDeleteBySetmealIds">
delete from setmeal_dish where setmeal_id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
4. 修改套餐
1 需求分析和设计
接口设计(共涉及到5个接口):
根据id查询套餐
根据类型查询分类(已完成)
根据分类id查询菜品(已完成)
图片上传(已完成)
修改套餐
2 代码实现
1 根据id查询套餐
SetmealController
@GetMapping("/{id}")
@ApiOperation("根据id查询套餐")
public Result querySetmealById(@PathVariable("id") Long id) {
return setmealService.querySetmealById(id);
}
----------
SetmealService
/**
* 根据id查询套餐
* @param id
* @return
*/
Result querySetmealById(Long id);
-----------
SetmealServiceImpl
@Override
public Result querySetmealById(Long id) {
//查询套餐信息
Setmeal setmeal = setmealMapper.selectById(id);
//查询套餐关联的菜品列表
List<SetmealDish> setmealDishes = setmealDishMapper.selectBySetmealId(id);
//封装成VO对象
SetmealVO vo = new SetmealVO();
BeanUtils.copyProperties(setmeal, vo);
vo.setSetmealDishes(setmealDishes);
return Result.success(vo);
}
----------
SetmealMapper
/**
* 根据id查询套餐
* @param id
* @return
*/
@Select("select * from setmeal where id = #{id}")
Setmeal selectById(Long id);
----------
SetmeatlDishMapper
/**
* 根据套餐id,查询套餐内包含的菜品
* @param setmealId
* @return
*/
@Select("select * from setmeal_dish where setmeal_id = #{setmealId}")
List<SetmealDish> selectBySetmealId(Long setmealId);
2 修改套餐
SetmealController
@PutMapping
@ApiOperation("修改套餐")
public Result updateSetmeal(@RequestBody SetmealDTO dto){
return setmealService.updateSetmeal(dto);
}
----------
SetmealService
/**
* 修改套餐
* @param dto
* @return
*/
Result updateSetmeal(SetmealDTO dto);
----------
SetmealServiceImpl
@Override
@Transactional
public Result updateSetmeal(SetmealDTO dto) {
//1. 修改套餐
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(dto, setmeal);
setmealMapper.updateById(setmeal);
//2. 修改套餐关联的菜品
//2.1 删除套餐 之前关联的菜品
setmealDishMapper.batchDeleteBySetmealIds(Collections.singletonList(dto.getId()));
//2.2 重新添加 关联的菜品
List<SetmealDish> setmealDishes = dto.getSetmealDishes();
if (setmealDishes != null && setmealDishes.size() > 0) {
setmealDishes.forEach(setmealDish -> setmealDish.setSetmealId(setmeal.getId()));
setmealDishMapper.batchInsert(setmealDishes);
}
return Result.success();
}
-----------
SetmealMapper
/**
* 根据id修改套餐
* @param setmeal
*/
@AutoFill(OperationType.UPDATE)
void updateById(Setmeal setmeal);
-----------
SetmealMapper.xml
<update id="updateById">
UPDATE setmeal
<set>
<if test="categoryId!=null">category_id = #{categoryId},</if>
<if test="name!=null and name.length()>0">name = #{name},</if>
<if test="price!=null">price = #{price},</if>
<if test="status!=null">status = #{status},</if>
<if test="description!=null and description.length()>0">description = #{description},</if>
<if test="image!=null and image.length()>0">image = #{image},</if>
<if test="updateTime!=null">update_time = #{updateTime},</if>
<if test="updateUser!=null">update_user = #{updateUser}</if>
</set>
WHERE id = #{id}
</update>
5. 起售停售套餐
1 需求分析和设计
业务规则:
可以对状态为起售的套餐进行停售操作,可以对状态为停售的套餐进行起售操作
起售的套餐可以展示在用户端,停售的套餐不能展示在用户端
起售套餐时,如果套餐内包含停售的菜品,则不能起售
2 代码实现
SetmealController
@PostMapping("/status/{status}")
@ApiOperation("启用禁用套餐")
public Result updateStatus(@PathVariable("status") Integer status, Long id){
return setmealService.updateStatus(id, status);
}
--------------
SetmealService
/**
* 套餐起售、停售
* @param status
* @param id
*/
Result updateStatus(Long id, Integer status);
-------------
SetmealServiceImpl
@Autowired
private DishMapper dishMapper;
@Override
public Result updateStatus(Long id, Integer status) {
//起售套餐时,如果包含了“停售”状态的菜品,则不允许起售
if (StatusConstant.ENABLE.equals(status)) {
//查询套餐关联的所有菜品
List<Dish> dishes = dishMapper.selectBySetmealId(id);
//如果有任意一个菜品是“停售”状态,就抛出异常
long count = dishes.stream()
.filter(dish -> dish.getStatus().equals(StatusConstant.DISABLE))
.count();
if (count > 0) {
throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);
}
}
//起售/停售套餐
Setmeal setmeal = Setmeal.builder()
.id(id)
.status(status)
.build();
setmealMapper.updateById(setmeal);
return Result.success();
}
-----------
DishMapper
/**
* 根据套餐id查询菜品
* @param setmealId
* @return
*/
@Select("select * from dish where id in(select dish_id from setmeal_dish where setmeal_id = #{setmealId})")
List<Dish> selectBySetmealId(Long setmealId);