瑞吉外卖 - 删除分类功能(13)

某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548

1.需求分析

在分类管理页面,可以对某个分类进行删除操作。但是需要注意的是,当分类关联了菜品或者套餐时,此分类不允许删除。

2.代码开发

2.1 执行过程分析

在开发代码之前,需要梳理一下整个程序的执行过程:

  1. 页面发送 ajax 请求,将参数(id)提交到服务端;
  2. 服务端 Controller 接收页面提交的数据并调用 Service 删除数据;
  3. Service 调用 Mapper 操作数据库。

下面同样简单看一下对应客户端发送的请求信息:

2.2 代码实现

注意,因为当分类关联了菜品或者套餐时,此分类不允许删除。因此,我们不能简单的调用 MyBatis Plus 提供的 categoryService.removeById(id) 方法直接进行删除。而是需要检查删除的分类是否关联了菜品或者套餐,因此我们需要进行一些功能上的扩展。

要完善分类删除功能,需要先准备基础的类和接口。首先需要实体类 DishSetmeal,菜品和套餐这两个实体类在前面同意导入实体的时候已经导入了,直接使用即可。

2.2.1 准备实体类

entity/Dish.java 实体类完整代码如下:

package cn.javgo.reggie_take_out.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 菜品
 */
@Data
public class Dish implements Serializable {
    
    
    // 用于序列化的版本号
    private static final long serialVersionUID = 1L;

    // 主键
    private Long id;

    //菜品名称
    private String name;

    //菜品分类id
    private Long categoryId;

    //菜品价格
    private BigDecimal price;

    //商品码
    private String code;

    //图片
    private String image;

    //描述信息
    private String description;

    //0 停售 1 起售
    private Integer status;

    //顺序
    private Integer sort;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

    //是否删除
    private Integer isDeleted;
}

entity/Setmeal.java 实体类完整代码如下:

package cn.javgo.reggie_take_out.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 套餐
 */
@Data
public class Setmeal implements Serializable {
    
    
    // 用于序列化的版本号
    private static final long serialVersionUID = 1L;

    // 主键
    private Long id;

    //分类id
    private Long categoryId;

    //套餐名称
    private String name;

    //套餐价格
    private BigDecimal price;

    //状态 0:停用 1:启用
    private Integer status;

    //编码
    private String code;

    //描述信息
    private String description;

    //图片
    private String image;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

    //是否删除
    private Integer isDeleted;
}

2.2.2 准备 Mapper 接口

对应的 mapper/DishMapper.java 接口如下:

package cn.javgo.reggie_take_out.mapper;

import cn.javgo.reggie_take_out.entity.Dish;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface DishMapper extends BaseMapper<Dish> {
    
    
    
}

对应的 mapper/SetmealMapper.java 接口如下:

package cn.javgo.reggie_take_out.mapper;

import cn.javgo.reggie_take_out.entity.Setmeal;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SetmealMapper extends BaseMapper<Setmeal> {
    
    
    
}

2.2.3 准备 Service 接口及实现类

对应的 service/DishService.java 接口如下:

package cn.javgo.reggie_take_out.service;

import cn.javgo.reggie_take_out.entity.Dish;
import com.baomidou.mybatisplus.extension.service.IService;

public interface DishService extends IService<Dish> {
    
    
    
}

对应的 service/impl/DishServiceImpl.java 实现类如下:

package cn.javgo.reggie_take_out.service.impl;

import cn.javgo.reggie_take_out.entity.Dish;
import cn.javgo.reggie_take_out.mapper.DishMapper;
import cn.javgo.reggie_take_out.service.DishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
    
    
    
}

对应的 service/SetmealService.java 接口如下:

package cn.javgo.reggie_take_out.service;

import cn.javgo.reggie_take_out.entity.Setmeal;
import com.baomidou.mybatisplus.extension.service.IService;

public interface SetmealService extends IService<Setmeal> {
    
    

}

对应的 service/impl/SetmealServiceImpl.java 实现类如下:

package cn.javgo.reggie_take_out.service.impl;

import cn.javgo.reggie_take_out.entity.Setmeal;
import cn.javgo.reggie_take_out.mapper.SetmealMapper;
import cn.javgo.reggie_take_out.service.SetmealService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {
    
    
    
}

2.2.4 自定义 remove 方法

想要实现我们的检查逻辑,就不能使用 MyBatis Plus 提供的现成方法了,我们需要在 CategoryService 接口中进行自定义:

public interface CategoryService extends IService<Category> {
    
    
    /**
     * 删除分类
     * @param id 分类id
     */
    public void remove(Long id);
}

然后在该接口的 CategoryServiceImpl 实现中进行抽象方法的实现:

@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
    
    
    @Resource
    private DishService dishService;

    @Resource
    private SetmealService setmealService;

    /**
     * 根据分类id删除分类,在删除之前判断是否关联了菜品和套餐,如果关联了则不能删除
     * @param id 分类id
     */
    @Override
    public void remove(Long id) {
    
    
        // 1.构造查询条件
        QueryWrapper<Dish> queryWrapper = new QueryWrapper<>();
        // 2.设置查询条件(根据分类id查询)
        queryWrapper.eq("category_id",id);
        // 3.查询到的菜品数量
        int count = dishService.count(queryWrapper);
        // 4.检查菜品数量,如果大于0则不能删除,抛出业务异常
        if (count > 0) {
    
    
            throw new CustomException("该分类下有菜品,不能删除");
        }

        // 5.构造查询条件
        QueryWrapper<Setmeal> queryWrapper2 = new QueryWrapper<>();
        // 6.设置查询条件(根据分类id查询)
        queryWrapper2.eq("category_id",id);
        // 7.查询到的套餐数量
        int count2 = setmealService.count(queryWrapper2);
        // 8.检查套餐数量,如果大于0则不能删除,抛出业务异常
        if (count2 > 0) {
    
    
            throw new CustomException("该分类下有套餐,不能删除");
        }

        // 9.删除分类
        baseMapper.deleteById(id);
    }
}

上述代码中涉及到的 common/CustomException.java 自定义业务异常如下:

package cn.javgo.reggie_take_out.common;

/**
 * 自定义业务异常
 */
public class CustomException extends RuntimeException {
    
    
    public CustomException(String message) {
    
    
        super(message);
    }
}

同时还需要在我们的 handler/GlobalExceptionHandler.java 全局异常处理器中进行该自定义异常的处理:

@ControllerAdvice(annotations = {
    
    RestController.class, Conditional.class})
@ResponseBody
public class GlobalExceptionHandler {
    
    

    /**
     * 处理自定义异常 CustomException
     * @param ex 异常对象
     * @return  响应对象
     */
    @ExceptionHandler(CustomException.class)
    public R<String> exceptionHandler(CustomException ex){
    
    
        return R.error(ex.getMessage());
    }
    
    // 省略其他方法
}

最后在 CategoryController 中编写对应的处理方法即可:

@RestController
@RequestMapping("/category")
public class CategoryController {
    
    
    @Resource
    private CategoryService categoryService;
    
    /**
     * 删除分类
     * @param id 分类id
     * @return R
     */
    @DeleteMapping
    public R<String> delete(Long id){
    
    
        categoryService.remove(id);
        return R.success("删除分类成功");
    }
    
    // 省略其他方法
}

3.功能测试

随便删除一个带有关联的分类进行删除操作:

新建一个没有关联的菜品分类:

删除新增的测试菜品,删除成功:

猜你喜欢

转载自blog.csdn.net/ly1347889755/article/details/130735697