当前位置: 首页 > news >正文

苍穹外卖资源点整理+个人错误解析-Day04-套餐模块

 一 需求

业务功能

- 新增套餐

- 套餐分页查询

- 删除套餐

- 修改套餐

- 起售停售套餐

要求

1. 根据产品原型进行需求分析,分析出业务规则

2. 设计接口

3. 梳理表之间的关系(分类表、菜品表、套餐表、口味表、套餐菜品关系表)

4. 根据接口设计进行代码实现

5. 分别通过swagger接口文档和前后端联调进行功能测试

二 代码

1.新增套餐

1.产品原型

业务规则:

 套餐名称唯一

 套餐必须属于某个分类

套餐必须包含菜品

名称、分类、价格、图片为必填项

添加菜品窗口需要根据分类类型来展示菜品

新增的套餐默认为停售状态

接口设计(共涉及到4个接口):

根据类型查询分类(已完成)

根据分类id查询菜品

图片上传(已完成)

新增套餐

根据类型查询分类

这项功能已完成

代码位于categorycontroller层。根据类型,也就是数据库中的type字段进行查询,而type类型定义则是在category实体层:

//类型: 1菜品分类 2套餐分类
private Integer type;

controller层
/*
根据类型查询分类
*/
@GetMapping("/list")
@ApiOperation("根据类型查询分类")
public Result<List<Category>> list(Integer type){
List<Category> list = categoryService.list(type);
return Result.success(list);
}

xml层:

<select id="list" resultType="Category">select * from categorywhere status = 1<if test="type != null">and type = #{type}</if>order by sort asc,create_time desc
</select>

根据分类id查询菜品

返回值是query类型。

首先分析查询逻辑可得, 我们想实现的效果大概是选择了一个分类就能显示出所有的菜品。

/*controller* 根据分类id查询菜品*/@GetMapping("/list")@ApiOperation("根据分类id查询菜品")public Result<List<Dish>> list(Long categoryId){List<Dish> list=dishService.list(categoryId);
return Result.success(list);}
@Override//serviceimpl
public List<Dish> list(Long categoryId) {Dish dish =Dish.builder().categoryId(categoryId).status(StatusConstant.ENABLE).build();//// 以上代码创建一个Dish对象,相当于以下的简写//Dish dish = new Dish();//dish.setCategoryId(categoryId);//dish.setStatus(StatusConstant.ENABLE);return dishMapper.list(dish);
}
//mapper.mxl
<select id="list" resultType="com.sky.entity.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>

实现效果:

新增套餐

如果想要新增套餐,需要新增的不只是单独的一个套餐,还要保证套餐与菜品的关系。所以需要写dishmapper以及setmealmapper,并且数据库中还有一个关联表setmealdish,所以:

由于要对多个表进行操作,我们得加上注解@Transactional在方法上以保证在对多个表进行数据操作时保证数据一致性,以下是impl层代码

@Transactionalpublic void saveWithDish(SetmealDTO setmealDTO) {Setmeal setmeal = new Setmeal();BeanUtils.copyProperties(setmealDTO,setmeal);//插入数据setmealMapper.insert(setmeal);//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>

插入数据后,会生成一个套餐id,我们得获取这个id并将这个id设置到detmealDish表中每个套餐菜品对象中,并且注意一个条件

//setmealdto中有套餐菜品关系
// private List<SetmealDish> setmealDishes = new ArrayList<>();

实现层代码:

List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();
//为每个 SetmealDish 对象设置 setmealId 字段,建立与 Setmeal 主表的关联关系
//将前端传入的 SetmealDTO 中的套餐菜品列表(setmealDishes)与刚创建的套餐记录进行关联setmealDishes.forEach(setmealDish -> {setmealDish.setSetmealId(setmealId);});//保存套餐与菜品的关联关系setmealDishMapper.insertBatch(setmealDishes);}

//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.套餐分页查询

1.分析

产品原型:

业务规则:

  • 根据页码进行分页展示
  • 每页展示10条数据
  • 可以根据需要,按照套餐名称、分类、售卖状态进行查询

以下是接口信息

封装成为Result<PageResult>,因为返回数据有这么多,code,msg,data是result对象,而data里的数据是pageresult里面的records对象。

2.代码

//分页查询controller@GetMapping("/page")@ApiOperation("分页查询")public Result<PageResult> page(SetmealPageQueryDTO setmealPageQueryDTO){log.info("分页查询:{}",setmealPageQueryDTO);PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);return Result.success(pageResult);}
}

//impl

public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {PageHelper.startPage(setmealPageQueryDTO.getPage(),setmealPageQueryDTO.getPageSize());Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);return new PageResult(page.getTotal(), page.getResult());
}
<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.分析

业务规则:

可以一次删除一个套餐,也可以批量删除套餐

起售中的套餐不能删除

2.代码

//删除controller
@DeleteMapping
@ApiOperation("批量删除")
public  Result delete(@RequestParam List<Long> ids){setmealService.deleteBatch(ids);return Result.success();//serviceimpl
@Transactionalpublic void deleteBatch(List<Long> ids) {//起售中的套餐不能删除for (Long id : ids) {Setmeal setmeal=  setmealMapper.getById(id);if (setmeal.getStatus()==StatusConstant.ENABLE){throw  new DeletionNotAllowedException(MessageConstant.SETMEAL_ON_SALE);}}//删除套餐表中数据for (Long id : ids) {setmealMapper.deleteById(id);setmealDishMapper.deleteBySetmealId(id);}}
//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.修改套餐

1.分析

接口设计(共涉及到5个接口):

 根据id查询套餐

根据类型查询分类(已完成)

根据分类id查询菜品(已完成)

图片上传(已完成)

修改套餐

为什么修改会有一个根据id查询菜品?

因为没有这个接口的话,进入修改界面信息是无法显示的,如图所示:

2.代码

根据id查询

由于需要对前端进行数据的回显,进行套餐查询时,也需要将菜品回显。使用setmealVO。

controller:

//根据id查询套餐@GetMapping("/{id}")@ApiOperation("根据id查询套餐")public Result<SetmealVO> getById(@PathVariable Long id){SetmealVO setmealVO =  setmealService.getByIdWithDish(id);return Result.success(setmealVO);}

impl:

写出方法后需要明确,我们进行根据id查询套餐,其实需要查询套餐以及套餐里的菜品。

所以现根据套餐id查询套餐,这一步的方法在之前已经存在getById,可以直接使用。并封装在一个setmeal对象中(因为查询的就是setseal数据)

随后需要根据套餐id查询相关联的菜品id,关联表为setmeal_Dish,在 setmealDishmapper进行查询,根据套餐id进行查询,并由于一个套餐可以关联多个菜品,因此为集合对象,并为setmealdish

最后为了让前端显示,需要将数据传入vo格式对象中,使用属性拷贝,然后由于setmealVO中有

//套餐和菜品的关联关系
private List<SetmealDish> setmealDishes = new ArrayList<>();

这一行属性,直接使用set进行赋值。

//根据id查询套餐@Overridepublic SetmealVO getByIdWithDish(Long id) {//根据id查询套餐和关联的菜品数据//查询套餐idSetmeal setmeal = setmealMapper.getById(id);//查询关联的菜品List<SetmealDish> setmealDishes= setmealDishMapper.getBySetmealId(id);SetmealVO setmealVO = new SetmealVO();BeanUtils.copyProperties(setmeal,setmealVO);setmealVO.setSetmealDishes(setmealDishes);return setmealVO;}
//setmealdishmapper:
//根据餐id查询菜品@Select("select * from setmeal_dish where setmeal_id = #{setmealId}")List<SetmealDish> getBySetmealId(Long id);

修改套餐

controller:

//修改套餐
@PutMapping
@ApiOperation("修改套餐")
public  Result update(@RequestBody SetmealDTO setmealDTO){
log.info("修改套餐:{}",setmealDTO);
setmealService.update(setmealDTO);
return Result.success();
}

impl:需要拆分步骤,首先第一步是修改套餐,需要注意的是使用的为setmealdto,然后给setmeal对象赋值,因为不需要dto里面的菜品集合。

修改完套餐之后需要考虑菜品问题,此处使用的是day03同款方法,即先将菜品统一删除在重新插入。

但是感觉可以自己删除想删除的菜品id并新增或者不新增。

@Override
@Transactional
public void update(SetmealDTO setmealDTO) {Setmeal setmeal = new Setmeal();BeanUtils.copyProperties(setmealDTO,setmeal);//修改套餐setmealMapper.update(setmeal);//针对套餐里的菜品,删除套餐菜品关联关系Long id = setmeal.getId();setmealDishMapper.deleteBySetmealId(id);//重新插入关联关系List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();for (SetmealDish setmealDish : setmealDishes) {setmealDishMapper.insertBatch(setmealDishes);}}

mapper.xml:

<!--    修改--><update id="update">update setmeal<set><if test="categoryId != null">category_id = #{categoryId},</if><if test="name != null">name = #{name},</if><if test="price != null">price = #{price},</if><if test="status != null">status = #{status},</if><if test="description != null">description = #{description},</if><if test="image != null">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.代码

//启用禁用套餐@PostMapping("/status/{status}")@ApiOperation("套餐启用禁用")public Result startOrStop(@PathVariable  Integer status,Long id){
log.info("启用禁用:{}{}",status,id);
setmealService.startOrStop(status,id);
return Result.success();}
@Overridepublic void startOrStop(Integer status, Long id) {//起售套餐时,判断套餐内是否有停售菜品,有停售菜品提示"套餐内包含未启售菜品,无法启售"if(status.equals(StatusConstant.ENABLE)){  //1  启用//select a.* from dish a left join setmeal_dish b on a.id = b.dish_id where b.setmeal_id = ?//左外连接查询,根据套餐id查询菜品以及对应的菜品套餐关系数据,a.*所以返回所有菜品数据List<Dish> dishList = dishMapper.getBySetmealId(id);if(dishList != null && dishList.size() > 0){//判断套餐中是否包含的有菜品,有才走if判断dishList.forEach(dish -> {//套餐中包含菜品,如果这个菜品的状态为禁用,则抛出异常if(StatusConstant.DISABLE.equals(dish.getStatus())){throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);}});}}//执行流程: 如果是起售套餐,套餐内有停售菜品,则抛出异常 不能起售//         如果是起售套餐,套餐内没有停售菜品,if执行完后跳出继续向下执行,执行更新//         如果是停售套餐,不走上面的if,直接进行更新状态。Setmeal setmeal = Setmeal.builder().id(id).status(status).build();setmealMapper.update(setmeal);//修改套餐时写了通用的修改sql}
}
http://www.dtcms.com/a/570811.html

相关文章:

  • 网站建设哪公司微信开发时间
  • 河南郑州网站顾问什么公司能做网站建设
  • 哪里可以买链接网站个人网站建设方案书备案
  • 平板网站建设网站开发三大元素
  • php做的网站建设微信导入wordpress
  • 自动驾驶大模型---特斯拉FSD模型架构终浮出水面
  • JAVA算法练习题day65
  • 引流网站怎么做建团购网站
  • 做网站的公司搞什么活动做轮播海报的网站
  • 基于python网站开发网站建设 贴吧
  • 怎么做音乐网站泰安八戒电子商务有限公司
  • 昆明网站开发公司哪家好兰州网站开发
  • 1.2演示案例
  • 微网站设计与开发网站建设啊
  • 电子商务网站软件建设的核心是河南省建设厅证件查询
  • 建设网站需要租用服务器成都网站建设公司盈利吗
  • 单页面网站多少钱wordpress做企业网站
  • 青岛seo白城seo
  • 数电基础:常见的组合逻辑电路模块(2)
  • 4 LlamaIndex 全流程实践:构建企业级智能文档问答系统
  • 电商网站设计公司排行榜个人视频网站应该怎么做
  • 关于nginx部署项目报错swool启动问题
  • 天津做网站哪家比较好网页设计建立站点实验报告
  • Windows核心编程中整型定义规范
  • 网站运营需要哪些知识网站编辑做图片用什么
  • 网站首页下拉广告网页登录界面制作
  • 电子工程建设信息网站二本网络工程就业前景
  • 网站建设需要c语言吗企业解决方案架构师
  • 网站做ulr跳转软件销售具体怎么做的
  • 高端品牌网站建设特点网页上做ppt的网站