itheima苍穹外卖项目学习笔记--Day4: 套餐管理 / Day5: 店铺营业状态设置

套餐管理

  • Day4
    • a. 新增套餐
    • b. 套餐分页查询
    • c. 删除套餐
    • d. 修改套餐
      • (1). 根据id查询套餐,并显示
      • (2). 再修改套餐
    • e. 起售停售套餐
  • Day5:店铺营业状态设置

Day4

a. 新增套餐

在SetmealController中,定义新增套餐的接口

/**
* 新增套餐
* @param setmealDTO
* @return
*/
@PostMapping
@ApiOperation("新增套餐")
public Result save(@RequestBody SetmealDTO setmealDTO){
    log.info("新增套餐:{}", setmealDTO);
    setmealService.saveWithDish(setmealDTO);
    return Result.success();
}

在SetmealServiceImpl中,实现新增套餐的方法,及其父类接口

/**
* 新增套餐
* @param setmealDTO
*/
@Override
@Transactional
public void saveWithDish(SetmealDTO setmealDTO) {
    Setmeal setmeal = new Setmeal();
    BeanUtils.copyProperties(setmealDTO, setmeal);

    // 向套餐表插入数据
    setmealMapper.save(setmeal);

    // 获取套餐的主键值
    Long setmealId = setmeal.getId();

    // 获取套餐数据
    List<SetmealDish> setmealDishList = setmealDTO.getSetmealDishes();
    if (!setmealDishList.isEmpty()){
        setmealDishList.forEach(setmealDish -> {
            setmealDish.setSetmealId(setmealId);
        });
        // 向setmealDish表插入n条数据
        setmealDishMapper.insertBatch(setmealDishList);
    }
}

在SetmealMapper中,定义新增套餐的方法

/**
* 新增套餐
*/
@AutoFill(OperationType.INSERT)
void save(Setmeal setmeal);

在SetmealMapper.xml文件中,写入动态SQL语句

<insert id="save" 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}, #{create_time}, #{update_time}, #{create_user}, #{update_user})
insert>

在SetmealDishMapper中,定义批量插入套餐菜品数据的方法

/**
* 批量插入套餐菜品数据
* @param setmealDishList
*/
void insertBatch(List<SetmealDish> setmealDishList);

在SetmealDishMapper.xml,写入批量插入套餐菜品数据的SQL动态语句

<insert id="insertBatch">
    insert into setmeal_dish (setmeal_id, dish_id, name, price, copies)
    VALUES
    <foreach collection="setmealDishList" item="sd" separator=",">
        (#{sd.setmealId}, #{sd.dishId}, #{sd.name}, #{sd.price}, #{sd.copies})
    foreach>
insert>

b. 套餐分页查询

业务规则:

  • 根据页码展示菜品信息
  • 每页展示10条数据
  • 分页查询时可以根据需要输入套餐名称、套餐分类、套餐状态进行查询

在SetmealController中创建分页接口

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

在SetmealServiceImpl中实现pagequery方法,及其父类接口

/**
* 套餐分页查询
* @param setmealPageQueryDTO
* @return
*/
@Override
public PageResult pageQuery(SetmealPageQueryDTO setmealPageQueryDTO) {
    PageHelper.startPage(setmealPageQueryDTO.getPage(), setmealPageQueryDTO.getPageSize());
    Page<SetmealVO> page = setmealMapper.pageQuery(setmealPageQueryDTO);
    return new PageResult(page.getTotal(), page.getResult());
}

在SetmealMapper中实现pagequery方法,动态SQL语句将写在xml文件中

/**
* 套餐分页查询
* @param setmealPageQueryDTO
* @return
*/
Page<SetmealVO> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO);

在SetmealMapper.xml中,写入分页查询的动态语句

<select id="pageQuery" resultType="com.sky.vo.SetmealVO">
    select s.* , c.name as categoryName from setmeal s LEFT OUTER JOIN category c on s.category_id = c.id
    <where>
        <if test="name != null">
        	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.update_time desc
select>

c. 删除套餐

业务规则:

  • 可以一次删除一个套餐,也可以批量删除菜品
  • 起售中的套餐不能删除
  • 删除菜品后,关联的套餐菜品数据也需要删除掉

SetmealController中,创建批量删除套餐接口

 /**
 * 批量删除套餐
 * @param ids
 * @return
 */
@DeleteMapping
@ApiOperation("批量删除套餐")
public Result delete(@RequestParam List<Long> ids){
    log.info("批量删除套餐:{}", ids);
    setmealService.deleteBatch(ids);
    return Result.success();
}

SetmealServiceImpl中,实现批量删除套餐方法,及其父类接口

/**
 * 批量删除套餐
 * @param ids
 */
@Override
@Transactional
public void deleteBatch(List<Long> ids) {
    if (ids.isEmpty()){
        return;
    }

    // 判断当前菜品是否能够删除---是否存在起售中的菜品
    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);
        // 根据套餐id删除套餐和菜品的关联关系
        setmealDishMapper.deleteBySetmealId(id);
    }
}

SetmealMapper中,创建删除套餐setmeal方法

/**
 * 根据主键id查询套餐
 * @param id
 * @return
 */
@Select("Select * from setmeal where id = #{id}")
Setmeal getById(Long id);

/**
 * 根据主键id删除套餐
 * @param id
 */
@Delete("Delete from setmeal where id = #{id}")
void deleteById(Long id);

SetmealDIshMapper中,创建删除套餐菜品setmeal_dish方法

/**
 * 根据套餐id删除套餐和菜品的关联关系
 * @param setmealId
 */
@Delete("Delete from setmeal_dish where setmeal_id = #{setmealId}")
void deleteBySetmealId(Long setmealId);

d. 修改套餐

(1). 根据id查询套餐,并显示

SetmealController,实现根据id查询套餐

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

SetmealServiceImpl中,实现根据id查询套餐,及其父类接口

  • 通过setmealMapper调用getById()接口
  • 通过setmealDishMapper获取套餐关联的菜品信息
/**
 * 根据id查询套餐
 * @param id
 * @return
 */
@Override
public SetmealVO getByIdWithDish(Long id) {
    Setmeal setmeal = setmealMapper.getById(id);
    List<SetmealDish> setmealDishList = setmealDishMapper.getDishBySetmealId(id);

    SetmealVO setmealVO = new SetmealVO();
    BeanUtils.copyProperties(setmeal, setmealVO);
    setmealVO.setSetmealDishes(setmealDishList);

    return setmealVO;
}

setmealDishMapper中,获取套餐关联的菜品信息

/**
 * 根据套餐id获取菜关联菜品的数据
 * @param setmealId
 * @return
 */
@Select("Select * from setmeal_dish where setmeal_id = #{setmealId}")
List<SetmealDish> getDishBySetmealId(Long setmealId);

(2). 再修改套餐

SetmealController,实现修改套餐接口

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

SetmealServiceImpl中,实现修改套餐方法,及其父类接口

/**
 * 修改套餐
 * @param setmealDTO
 */
@Override
@Transactional
public void updateWithDish(SetmealDTO setmealDTO) {
    Setmeal setmeal = new Setmeal();
    BeanUtils.copyProperties(setmealDTO, setmeal);

    // 修改套餐基本信息
    setmealMapper.update(setmeal);

    // 获取套餐id
    Long setmealId = setmealDTO.getId();

    // 删除原有的套餐关联的菜品信息,操作setmeal_dish表,执行delete
    setmealDishMapper.deleteBySetmealId(setmealId);

    // 获取套餐关联的菜品信息
    List<SetmealDish> setmealDishes = setmealDTO.getSetmealDishes();

    if (!setmealDishes.isEmpty()){
        setmealDishes.forEach(setmealDish -> {
            setmealDish.setSetmealId(setmealId);
        });
        // 重新向setmeal_dish表插入n条数据
        setmealDishMapper.insertBatch(setmealDishes);
    }
    }

SetmealMapper中,实现修改菜品的接口

/**
 * 根据Id修改套餐
 * @param setmeal
 */
@AutoFill(OperationType.UPDATE)
void update(Setmeal setmeal);

SetmealMapper.xml中,写入修改菜品的动态SQL语句

<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>

e. 起售停售套餐

业务规则:

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

在SetmealController中,实现套餐起售、停售接口

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

在SetmealServiceImpl中,实现套餐起售、停售方法,及其父类接口

/**
 * 启售停售套餐
 * @param status
 * @param id
 */
@Override
@Transactional
public void startOrStop(Integer status, Long id) {
    // 判断是起售/停售
    if (status == StatusConstant.ENABLE){
        // 先判断该套餐内的菜品是否包含停售菜品
        List<SetmealDish> setmealDishList = setmealDishMapper.getDishBySetmealId(id);
        if (!setmealDishList.isEmpty()) {
            setmealDishList.forEach(setmealDish -> {
                Long dishId = setmealDish.getDishId();
                Dish dish = dishMapper.getById(dishId);
                if (dish.getStatus() == StatusConstant.DISABLE){
                    // 套餐内有停售菜品
                    throw new SetmealEnableFailedException(MessageConstant.SETMEAL_ENABLE_FAILED);
                }
            });
        }
    }

    Setmeal setmeal = Setmeal.builder()
            .id(id)
            .status(status)
            .build();
    setmealMapper.update(setmeal);
}

Day5:店铺营业状态设置

接口设计:

  • 设置营业状态

  • 管理端查询营业状态

  • 用户端查询营业状态

本项目约定:

  • 管理端 发出的请求,统一使用 /admin 作为前缀

  • 用户端 发出的请求,统一使用 /user 作为前缀

  • 营业状态数据存储方式:基于Redis的字符串来进行存储

  • 约定:1表示营业 0表示打烊

  • 营业状态数据存储方式:基于Redis的字符串来进行存储

Key Value
SHOP_STATUS 1

在controller/admin/ShopController中,创建 “设置店铺的营业状态”和“获取店铺的营业状态” 接口方法

@RestController("adminShopController")
@RequestMapping("/admin/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {

    public static final String KEY = "SHOP_STATUS";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 设置店铺的营业状态
     * @param status
     * @return
     */
    @PutMapping("/{status}")
    @ApiOperation("设置店铺的营业状态")
    public Result setStatus(@PathVariable Integer status){
        log.info("设置店铺的营业状态:{}", status == 1? "营业中":"打烊中");
        redisTemplate.opsForValue().set(KEY, status);
        return Result.success();
    }

    /**
     * 获取店铺的营业状态
     * @return
     */
    @GetMapping("/status")
    @ApiOperation("获取店铺的营业状态")
    public Result<Integer> getStatus(){
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("获取到店铺的营业状态为:{}", status == 1? "营业中" : "打烊中");
        return Result.success(status);
    }
}

在controller/user/ShopController中,创建 “获取店铺的营业状态” 接口方法

@RestController("userShopController")
@RequestMapping("/user/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {

    public static final String KEY = "SHOP_STATUS";
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 获取店铺的营业状态
     * @return
     */
    @GetMapping("/status")
    @ApiOperation("获取店铺的营业状态")
    public Result<Integer> getStatus(){
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("获取到店铺的营业状态为:{}", status == 1? "营业中" : "打烊中");
        return Result.success(status);
    }
}

你可能感兴趣的:(苍穹外卖开发笔记,学习,笔记,java,spring,intellij-idea,spring,boot,mybatis)