套餐管理
- 1 任务
- 2 新增套餐
- 2.1 需求分析和设计
- 接口设计
- setmeal和setmeal_dish表设计
- 2.2 代码开发
- 2.2.1 根据分类id查询菜品
- DishController
- DishService
- DishServiceImpl
- DishMapper
- DishMapper.xml
- 2.2.2 新增套餐接口
- SetmealController
- SetmealService
- SetmealServiceImpl
- SetmealMapper 新增套餐
- SetmealMapper.xml
- SetmealDishMapper 保存套餐和菜品的关联关系
- SetmealDishMapper.xml
- 2.3 功能测试
- 3 套餐分页查询
- 3.1 需求分许和设计
- 3.2 代码实现
- SetmealController
- SetmealService
- SetmealServiceImpl
- SetmealMapper
- SetmealMapper.xml
- 3.3 测试
- 4 删除套餐
- 4.1 需求分析和设计
- 4.2 代码实现
- SetmealController
- SetmealService
- SetmealServiceImpl
- SetmealMapper
- SetmealDishMapper
- 4.3 功能测试
- 5 修改套餐
- 5.1 需求分析和设计
- 5.2 代码实现
- 5.3 功能测试
1 任务
完成套餐管理模块所有业务功能,包括:
- 新增套餐
- 套餐分页查询
- 删除套餐
- 修改套餐
- 起售停售套餐
要求:
- 根据产品原型进行需求分析,分析出业务规则
- 设计接口
- 梳理表之间的关系(分类表、菜品表、套餐表、口味表、套餐菜品关系表)
- 根据接口设计进行代码实现
- 分别通过swagger接口文档和前后端联调进行功能测试
2 新增套餐
2.1 需求分析和设计
以下是根据分类id查询菜品
1 字段:
1.1 排序:创建时间的倒序排列,单页最多显示10条
2 添加菜品
2.1点击添加菜品按钮,弹出添加菜品弹窗,菜品可以多选
2.2已选菜品数量超过7个显示滚动条,已选菜品列表根据添加时间倒序排列
3 字段限制
3.1 字段限制
3.2 套餐图片上传
点击上传图片,上传本地图片。再次点击,修改图片。
1 图片限制
图片大小不超过2M
仅能上传PNG JPG JPEG类型图片
建议上传200200或300300尺寸的图片
2 异常提示
图片过大,上传失败
格式错误,上传失败
3.3 套餐描述,选填,限制输入最大不超过200个汉字、字母大小写、阿拉伯数字。不符合限制提示,“套餐描述输入不符,请输入少于200个字”;
接口设计
需要用的接口:
- 根据分类id查询菜品
- 套餐管理中新增菜单接口
- 上传图片(完成)
- 根据类型查询分类(完成)
根据分类id查询菜品
套餐管理中新增菜单接口
setmeal和setmeal_dish表设计
setmeal表为套餐表,用于存储套餐的信息。
字段名 | 数据类型 | 说明 | 备注 |
---|---|---|---|
id | bigint | 主键 | 自增 |
name | varchar(32) | 套餐名称 | 唯一 |
category_id | bigint | 分类id | 逻辑外键 |
price | decimal(10,2) | 套餐价格 | |
image | varchar(255) | 图片路径 | |
description | varchar(255) | 套餐描述 | |
status | int | 售卖状态 | 1起售 0停售 |
create_time | datetime | 创建时间 | |
update_time | datetime | 最后修改时间 | |
create_user | bigint | 创建人id | |
update_user | bigint | 最后修改人id |
setmeal_dish表为套餐菜品关系表,用于存储套餐和菜品的关联关系。
字段名 | 数据类型 | 说明 | 备注 |
---|---|---|---|
id | bigint | 主键 | 自增 |
setmeal_id | bigint | 套餐id | 逻辑外键 |
dish_id | bigint | 菜品id | 逻辑外键 |
name | varchar(32) | 菜品名称 | 冗余字段 |
price | decimal(10,2) | 菜品单价 | 冗余字段 |
copies | int | 菜品份数 |
2.2 代码开发
- 根据分类id查询菜品
- 新增套餐接口
2.2.1 根据分类id查询菜品
DishController
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public Result<List<Dish>> list(Long categoryId){
List<Dish> list = dishService.list(categoryId);
return Result.success(list);
}
DishService
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/
List<Dish> list(Long categoryId);
DishServiceImpl
/**
* 根据分类id查询菜品
* @param categoryId
* @return
*/
public List<Dish> list(Long categoryId) {
Dish dish = Dish.builder()
.categoryId(categoryId)
.status(StatusConstant.ENABLE)
.build();
return dishMapper.list(dish);
}
DishMapper
/**
* 动态条件查询菜品
* @param dish
* @return
*/
List<Dish> list(Dish dish);
DishMapper.xml
<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>
2.2.2 新增套餐接口
SetmealController
/**
* 套餐管理
*/
@RestController
@RequestMapping("/admin/setmeal")
@Api(tags = "套餐相关接口")
@Slf4j
public class SetmealController {
@Autowired
private SetmealService setmealService;
/**
* 新增套餐
* @param setmealDTO
* @return
*/
@PostMapping
@ApiOperation("新增套餐")
public Result save(@RequestBody SetmealDTO setmealDTO) {
setmealService.saveWithDish(setmealDTO);
return Result.success();
}
}
SetmealService
public interface SetmealService {
/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @param setmealDTO
*/
void saveWithDish(SetmealDTO setmealDTO);
}
SetmealServiceImpl
/**
* 套餐业务实现
*/
@Service
@Slf4j
public class SetmealServiceImpl implements SetmealService {
@Autowired
private SetmealMapper setmealMapper;
@Autowired
private SetmealDishMapper setmealDishMapper;
@Autowired
private DishMapper dishMapper;
/**
* 新增套餐,同时需要保存套餐和菜品的关联关系
* @param setmealDTO
*/
@Transactional
public void saveWithDish(SetmealDTO setmealDTO) {
Setmeal setmeal = new Setmeal();
BeanUtils.copyProperties(setmealDTO, setmeal);
//向套餐表插入数据
setmealMapper.insert(setmeal);
//获取生成的套餐id
Long setmealId = setmeal.getId();
List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
setmealDishes.forEach(setmealDish -> {
setmealDish.setSetmealId(setmealId);
});
//保存套餐和菜品的关联关系
setmealDishMapper.insertBatch(setmealDishes);
}
}
SetmealMapper 新增套餐
/**
* 新增套餐
* @param setmeal
*/
@AutoFill(OperationType.INSERT)
void insert(Setmeal setmeal);
SetmealMapper.xml
<insert id="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>
SetmealDishMapper 保存套餐和菜品的关联关系
/**
* 批量保存套餐和菜品的关联关系
* @param setmealDishes
*/
void insertBatch(List<SetmealDish> setmealDishes);
SetmealDishMapper.xml
<insert id="insertBatch" parameterType="list">
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.3 功能测试
3 套餐分页查询
3.1 需求分许和设计
产品原型和业务规则
- 根据页码进行分页展示
- 每页展示10条数据
- 可以根据需要,按照套餐名称、分类、售卖状态进行查询
接口设计
查看Apifox
3.2 代码实现
这个建议参考之前实现的分页功能
SetmealController
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("分页查询")
public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO) {
PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);
return Result.success(pageResult);
}
SetmealService
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/
PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
SetmealServiceImpl
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/
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());
}
SetmealMapper
/**
* 分页查询
* @param setmealPageQueryDTO
* @return
*/
Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);
SetmealMapper.xml
<select id="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>
<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.3 测试
4 删除套餐
4.1 需求分析和设计
产品原型和
见资料
业务规则
- 可以一次删除一个套餐,也可以批量删除套餐
- 起售中的套餐不能删除
接口设计
4.2 代码实现
SetmealController
/**
* 批量删除套餐
* @param ids
* @return
*/
@DeleteMapping
@ApiOperation("批量删除套餐")
public Result delete(@RequestParam List<Long> ids){
setmealService.deleteBatch(ids);
return Result.success();
}
SetmealService
/**
* 批量删除套餐
* @param ids
*/
void deleteBatch(List<Long> ids);
SetmealServiceImpl
/**
* 批量删除套餐
* @param ids
*/
@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);
});
}
SetmealMapper
/**
* 根据id查询套餐
* @param id
* @return
*/
@Select("select * from setmeal where id = #{id}")
Setmeal getById(Long id);
/**
* 根据id删除套餐
* @param setmealId
*/
@Delete("delete from setmeal where id = #{id}")
void deleteById(Long setmealId);
SetmealDishMapper
/**
* 根据套餐id删除套餐和菜品的关联关系
* @param setmealId
*/
@Delete("delete from setmeal_dish where setmeal_id = #{setmealId}")
void deleteBySetmealId(Long setmealId);
4.3 功能测试
5 修改套餐
5.1 需求分析和设计
页面原型和业务规则
-
套餐名称唯一
-
套餐必须属于某个分类
-
套餐必须包含菜品
-
名称、分类、价格、图片为必填项
-
添加菜品窗口需要根据分类类型来展示菜品
-
新增的套餐默认为停售状态
接口设计 -
根据id查询套餐
-
修改套餐
-
根据类型查询分类(已完成)
-
根据分类id查询菜品(已完成)
-
图片上传(已完成)