前期文章
文章标题 | 地址 |
---|---|
苍穹外卖Day01——总结1 | https://lushimeng.blog.csdn.net/article/details/135466359 |
苍穹外卖Day01——解决总结1中存在的问题 | https://lushimeng.blog.csdn.net/article/details/135473412 |
苍穹外卖Day02——总结2 | https://lushimeng.blog.csdn.net/article/details/135484126 |
苍穹外卖Day02——解决总结2中存在的问题 | https://lushimeng.blog.csdn.net/article/details/136242268 |
总结3—菜品管理模块
- 1. 菜品管理效果图
- 2. 新增菜品模块
- 3. 分页查询模块
- 4. 删除菜品模块
- 5. 修改菜品模块
- 6. 总结
1. 菜品管理效果图
分页查询界面
新增菜品界面
2. 新增菜品模块
新增菜品界面:
业务规则:
- 菜品名称必须是唯一的
- 菜品必须属于某个菜品分类categorey下,不能单独存在
- 新增菜品时可以根据情况选择菜品的口味
- 每个菜品必须对应一张图片
接口需求:
- 查询菜品分类接口
- 上传图片接口,这里把图片存在在阿里云OOS
- 保存菜品接口
前两个接口都比较简单,这里需要介绍一下第三个接口:保存菜品接口,由于一个菜品包含多个口味,多以在插入菜品dish的同时还需要把菜品的口味插入到另一个独立的dish_flavour中。这里在插入菜品dish的时候需要使用主键回填的技术,这样才能为每个口味添加对应的dish_id。
DishServiceImpl:
/**
* 菜品添加
* @param dishDTO
*/
@Transactional
public void saveWithFlavor(DishDTO dishDTO) {
// 1. 添加菜品
Dish dish = new Dish();
BeanUtils.copyProperties(dishDTO, dish);
dishMapper.saveDish(dish);
// 主键回填技术, 用于后续给每个口味添加对应的菜品dish_id
Long dishId = dish.getId();
// 2. 添加菜品的口味
List<DishFlavor> flavors = dishDTO.getFlavors();
flavors.forEach(flavor -> flavor.setDishId(dishId));
dishFlavorMapper.saveBatch(flavors); // 批量添加
}
DishMapper.xml
<!--主键回填-->
<insert id="saveDish" useGeneratedKeys="true" keyProperty="id">
insert into dish (name, category_id, price, image, description, create_time, update_time, create_user,update_user, status)
values
(#{name}, #{categoryId}, #{price}, #{image}, #{description}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser}, #{status})
</insert>
3. 分页查询模块
分页查询效果图:
分页查询不是很熟悉,这里就详细的介绍一下整体的流程。
步骤一:确定前端传递的参数以及后端需要返回的数据格式
前端传递参数:
@Data
public class DishPageQueryDTO implements Serializable {
private int page;
private int pageSize;
private String name;
//分类id
private Integer categoryId;
//状态 0表示禁用 1表示启用
private Integer status;
}
后端返回数据格式:
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PageResult implements Serializable {
private long total; //总记录数
private List records; //当前页数据集合
}
步骤二:确定接口
DishController:
/**
* 分页查询
*
* @param dishPageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("分页查询接口")
public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
log.info("分页查询:{}", dishPageQueryDTO);
PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
return Result.success(pageResult);
}
DishServiceImpl:
这里使用PageHelper插件。首先调用startPage方法,开始分页查询;然后获取查询信息,这里返回统一为Page page;然后根据获取的page得到查询总数以及每条查询信息集合。下面代码是固定的套路,记住即可。
/**
* 分页查询
* @param dishPageQueryDTO
* @return
*/
public PageResult pageQuery(DishPageQueryDTO dishPageQueryDTO) {
// 开始分页查询
PageHelper.startPage(dishPageQueryDTO.getPage(), dishPageQueryDTO.getPageSize());
// 获取分页查询page, 固定写法
Page<DishVO> page = dishMapper.pageQuery(dishPageQueryDTO);
long total = page.getTotal(); // 获取总数
List<DishVO> records = page.getResult(); // 获取内容
return new PageResult(total, records);
}
DishMapper.xml:
这里使用了多表联查:“select d.* , c.name as categoryName from dish d left outer join category c on d.category_id = c.id
”
给表起别名、表字段起别名以及联合查询。要特别学一下这种思想,经常在分页查询中用到。
<select id="pageQuery" parameterType="com.sky.dto.DishPageQueryDTO" 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 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>
4. 删除菜品模块
删除菜品:
业务规则:
- 可以一次删除一个菜品,也可以批量删除菜品,因为一次删除多个菜品包括一次删除一个,所以只需要一个接口即可:一次删除多个。
- 起售中的菜品不能删除
- 被套餐关联的菜品不能删除
- 删除菜品后,关联的口味数据也需要删除掉
上述接口比较简单,只需要弄清业务规则即可,特别是在删除菜品的时候需要该菜品是否有关联项,能否不考虑其他部分直接删除。
5. 修改菜品模块
修改菜品界面:
在修改菜品的时候需要回显菜品相关信息,该页面共涉及4个接口。
接口:
- 根据id查询菜品
- 根据类型查询分类
- 文件上传
- 修改菜品
修改注意事项:
- 菜品数据回显
- 修改菜品时候可能会修改菜品口味,正确的做法是删除该菜品对应的所有口味,然后插入新传入的口味信息
- 云资源浪费为题。如果换了图片原来的图片还存储在云上会造成资源浪费,猜测后续使用redis删除无用的照片,插入到云上的图片也存入到redis中,redis上的图片信息和运算的图片信息进行比对,然后删除多余文件信息,减少云资源浪费
6. 总结
收获:
- CURD:
Controller -> service -> serviceImpl -> mapper -> mapper.xml
; - 前端到后端数据:XXXDTO, 后端返回给前端数据:XXXVO;
- 分页查询有自己一套模板,使用分页插件,记住就行;
- 业务逻辑分析:
- 删除模块:在删除的时候需要考虑该信息是否关联其他信息?
- 修改模块:如果该信息关联其他模块,修改了该信息其他信息是否会修改,原来的信息怎么办?
补充内容:
内容1:字段填充,由于每个模块都含有创建时间、创建人、更新时间和更新人信息,每次都需要setXXX进行设置,太繁琐,提出了字段填充。本项目提出的字段填充使用到: AOP, 反射,主键等技术;
内容2:@RequestBody、@RequestParam、@PathVariable用法区别;
内容3:阿里云云存储。