【学习日记2023.5.22】 之 套餐模块完善

news/2024/11/8 16:36:42/

4. 功能模块完善之套餐模块

4.1 新增套餐

4.1.1 需求分析与设计

产品原型

后台系统中可以管理套餐信息,通过 新增功能来添加一个新的套餐,在添加套餐时需要添加套餐对应菜品的信息,并且需要上传套餐图片。

新增套餐原型:
请添加图片描述
请添加图片描述

当填写完表单信息, 点击"保存"按钮后, 会提交该表单的数据到服务端, 在服务端中需要接受数据, 然后将数据保存至数据库中。

业务规则:

  • 套餐名称必须是唯一的
  • 套餐必须属于某个分类
  • 套餐必须包含菜品
  • 名称、分类、价格、图片为必填项
  • 添加菜品窗口需要根据分类类型来展示菜品
  • 新增的套餐默认为停售状态

接口设计

  • 根据类型查询分类(已完成)
  • 根据分类id查询菜品
  • 文件上传(已完成)
  • 新增套餐

根据分类id查询菜品
请添加图片描述

新增套餐
请添加图片描述

数据库设计:

setmeal表为套餐表,用于存储套餐的信息。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)套餐名称唯一
category_idbigint分类id逻辑外键
pricedecimal(10,2)套餐价格
imagevarchar(255)图片路径
descriptionvarchar(255)套餐描述
statusint售卖状态1起售 0停售
create_timedatetime创建时间
update_timedatetime最后修改时间
create_userbigint创建人id
update_userbigint最后修改人id

setmeal_dish表为套餐菜品关系表,用于存储套餐和菜品的关联关系。具体表结构如下:

字段名数据类型说明备注
idbigint主键自增
setmeal_idbigint套餐id逻辑外键
dish_idbigint菜品id逻辑外键
namevarchar(32)菜品名称冗余字段
pricedecimal(10,2)菜品单价冗余字段
copiesint菜品份数

4.1.2 代码开发

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>

SetmealController

/*** 套餐管理*/
@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();}
}

SetmealService

public interface SetmealService {/*** 新增套餐,同时需要保存套餐和菜品的关联关系* @param setmealDTO*/void saveWithDish(SetmealDTO setmealDTO);
}

SetmealServiceImpl

/*** 套餐业务实现*/
@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);}
}

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>

4.1.3 功能测试

接口文档测试

  • 根据分类id查询菜品
    请添加图片描述

  • 新增套餐
    请添加图片描述

前后端联调

  • 根据分类id查询菜品
    请添加图片描述

  • 新增套餐
    请添加图片描述

4.1.4 提交代码

commit—>describe—>push

4.2 套餐分页查询

4.2.1 需求分析与设计

产品原型

系统中的套餐数据很多的时候,如果在一个页面中全部展示出来会显得比较乱,不便于查看,所以一般的系统中都会以分页的方式来展示列表数据。

套餐分页原型:
请添加图片描述

在套餐列表展示时,除了套餐的基本信息(名称、售价、售卖状态、最后操作时间)外,还有两个字段略微特殊,第一个是图片字段 ,从数据库查询出来的仅仅是图片的名字,图片要想在表格中回显展示出来,就需要下载这个图片。第二个是套餐分类,这里展示的是分类名称,而不是分类ID,此时就需要根据套餐的分类ID,去分类表中查询分类信息,然后在页面展示。

业务规则:

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

接口设计
请添加图片描述

4.2.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">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>

4.2.3 功能测试

接口文档测试和前后端联调测试
请添加图片描述
请添加图片描述

4.2.4 提交代码

commit—>describe—>push

4.3 删除套餐

4.3.1 需求分析与设计

产品原型:
请添加图片描述

业务规则:

  • 可以一次删除一个套餐,也可以批量删除套餐
  • 起售中的套餐不能删除

接口设计:
请添加图片描述

4.3.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.3 功能测试

请添加图片描述

接口文档测试

  • 删除起售中的套餐
    请添加图片描述

  • 删除停售的套餐
    请添加图片描述

前后端联调
请添加图片描述
请添加图片描述

4.3.4 提交代码

commit—>describe—>push

4.4 修改套餐

4.4.1 需求分析与设计

产品原型:
请添加图片描述

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

  • 根据id查询套餐
  • 根据类型查询分类(已完成)
  • 根据分类id查询菜品(已完成)
  • 图片上传(已完成)
  • 修改套餐

根据id查询套餐
请添加图片描述

修改套餐
请添加图片描述

4.4.2 代码开发

SetmealController

/*** 根据id查询套餐,用于修改页面回显数据** @param id* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询套餐")
public Result<SetmealVO> getById(@PathVariable Long id) {SetmealVO setmealVO = setmealService.getByIdWithDish(id);return Result.success(setmealVO);
}/*** 修改套餐** @param setmealDTO* @return
*/
@PutMapping
@ApiOperation("修改套餐")
public Result update(@RequestBody SetmealDTO setmealDTO) {setmealService.update(setmealDTO);return Result.success();
}

SetmealService

/*** 根据id查询套餐和关联的菜品数据* @param id* @return
*/
SetmealVO getByIdWithDish(Long id);/*** 修改套餐* @param setmealDTO
*/
void update(SetmealDTO setmealDTO);

SetmealServiceImpl

/*** 根据id查询套餐和套餐菜品关系** @param id* @return
*/
public SetmealVO getByIdWithDish(Long id) {SetmealVO setmealVO = setmealMapper.getByIdWithDish(id);return setmealVO;
}/*** 修改套餐** @param setmealDTO
*/
@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);
}

SetmealMapper

/*** 根据id查询套餐和套餐菜品关系* @param id* @return
*/
SetmealVO getByIdWithDish(Long id);

SetmealMapper.xml

<resultMap id="setmealAndDishMap" type="com.sky.vo.SetmealVO" autoMapping="true"><result column="id" property="id"/><collection property="setmealDishes" ofType="SetmealDish"><result column="sd_id" property="id"/><result column="setmeal_id" property="setmealId"/><result column="dish_id" property="dishId"/><result column="sd_name" property="name"/><result column="sd_price" property="price"/><result column="copies" property="copies"/></collection>
</resultMap>
<select id="getByIdWithDish" parameterType="long" resultMap="setmealAndDishMap">select a.*,b.id    sd_id,b.setmeal_id,b.dish_id,b.name  sd_name,b.price sd_price,b.copiesfrom setmeal aleft joinsetmeal_dish bona.id = b.setmeal_idwhere a.id = #{id}
</select>

4.4.3 功能测试

接口文档测试

  • 根据id查询套餐
    请添加图片描述

  • 修改套餐
    请添加图片描述

前后端联调

  • 数据回显
    请添加图片描述

  • 修改套餐
    请添加图片描述

4.4.4 提交代码

commit—>describe—>push

4.5 起售停售套餐

4.5.1 需求分析与设计

产品原型:
请添加图片描述

业务规则:

  • 可以对状态为起售的套餐进行停售操作,可以对状态为停售的套餐进行起售操作
  • 起售的套餐可以展示在用户端,停售的套餐不能展示在用户端
  • 起售套餐时,如果套餐内包含停售的菜品,则不能起售

接口设计:
请添加图片描述

4.5.2 代码开发

SetmealController

/*** 套餐起售停售* @param status* @param id* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("套餐起售停售")
public Result startOrStop(@PathVariable Integer status, Long id) {setmealService.startOrStop(status, id);return Result.success();
}

SetmealService

/*** 套餐起售、停售* @param status* @param id
*/
void startOrStop(Integer status, Long id);

SetmealServiceImpl

/*** 套餐起售、停售* @param status* @param id
*/
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);
}

DishMapper

/*** 根据套餐id查询菜品* @param setmealId* @return
*/
@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);

4.5.3 功能测试

请添加图片描述

起售、停售套餐

  • 起售:套餐内含未启用菜品
    请添加图片描述

  • 停售
    请添加图片描述

前后端联调

  • 起售
    请添加图片描述

  • 停售
    请添加图片描述

4.5.4 提交代码

commit—>describe—>push


http://www.ppmy.cn/news/85181.html

相关文章

【解决】前端项目编译卡在95% emitting HtmlWebpackPlugin很长时间

快速出击 原因 &#xff1a;问题原因最终定位在部分依赖版本不兼容&#xff0c;不适配。 解决方案 &#xff1a;删除node_modules文件夹&#xff0c;拷贝编译速度不慢人员电脑中的package-lock.json文件&#xff0c;然后执行npm install&#xff08;或者直接把node_modules打包…

GitLab Dogfooding 实践:Web API 模糊测试

本文来源&#xff1a;about.gitlab.com 作者&#xff1a;Eugene Lim&#xff0c;Mike Eddington 译者&#xff1a;极狐(GitLab) 市场部内容团队 在极狐GitLab/GitLab 内部&#xff0c;我们用 Dogfooding 文化来帮助更好地理解产品、解决痛点以及配置错误&#xff0c;构建一个更…

数据库学习2

加密函数 SELECT USER() FROM DUAL;--用户ip地址 SELECT DATABASE();--查看当前数据库名称 SELECT MD5(hsp) FROM DUAL;--为字符串算出32字符串&#xff0c;常用加密 SELECT LENGTH(MD5(hsp)) FROM DUAL; CREATE TABLE hsp_user( id INT, name VARCHAR(32) NOT NULL DEFAULT ,…

ES6:var 、const、let的使用和区别

前言 本文主要介绍了ES6中var、const、let的使用和区别 基本介绍 let let声明变量 const const :声明常量const声明的常量可以修改,但不能重新赋值 如&#xff1a;以下代码是正确的&#xff1a; //引用数据类型 const info {name:Candy }; info.nameJune;而下面的代码是…

AWS设备自定义身份认证

AWS设备自定义身份认证需要通过lambda服务实现&#xff0c;具体来说&#xff0c;首先需要创建一个lambda函数&#xff0c;在函数中实现具体的认证逻辑&#xff0c;然后Iot在调用授权方时&#xff0c;将触发lambda函数&#xff0c;返回认证结果。 1.输入参数说明 授权方在调用…

[论文评析]mixup: B EYOND E MPIRICAL R ISK M INIMIZATION, ICLR 2018,

mixup: B EYOND E MPIRICAL R ISK M INIMIZATION 介绍MixupMixup的提出动机Mixup与常规数据增广方法的区别References 介绍 采用ERM训练的模型往往存在泛化能力差的情形-可能是在简单的记忆样本, 对于噪声干扰的鲁棒性很差. 这篇论文提出了一种新的数据增广方法-Mixup, 这里主…

字符串、字符串列表,倒序生成字典。

带数字的字符串以数字为key倒序生成字典&#xff0c;字符串列表按其元素索引为key倒序生成字典。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简…

飞鲨展览:2023山东老博会,11月移师济南黄河国际会展中心

新展馆、新起点、新征程-CSOLDE2023第5届中国&#xff08;济南&#xff09;国际养老服务业展览会2023 Fifth China (Jinan) International Old-age Services Exhibition&#xff0c;移师济南黄河国际会展中心举办的通告 尊敬的参展商、观众、媒体及行业人士&#xff1a; 为了更…