03-瑞吉外卖关于菜品/套餐分类表的增删改查

新增菜品/套餐分类

页面原型

当我们在后台系统中添加菜品/套餐时,需要选择一个菜品/套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐

第一步: 用户点击确定按钮执行submitForm函数发送Ajax请求,将新增菜品/套餐表单中输入的数据以json形式提交给服务端,等待服务端响应数据后执行回调函数

html 复制代码
<!--用户在表单页面category/list.html中填写分类名称和排序数字-->
<el-form class="demo-form-inline" label-width="100px">
        <el-form-item label="分类名称:">
          <el-input v-model="classData.name" placeholder="请输入分类名称" maxlength="14"/>
        </el-form-item>
        <el-form-item label="排序:">
          <el-input v-model="classData.sort"  type="number" placeholder="请输入排序" />
        </el-form-item>
</el-form>
      <span slot="footer" class="dialog-footer">
        <el-button size="medium" @click="classData.dialogVisible = false">取 消</el-button>
        <el-button type="primary" size="medium" @click="submitForm()">确 定</el-button>
 <el-button v-if="action != 'edit'" type="primary" size="medium" class="continue" @click="submitForm('go')"> 保存并继续添加 </el-button>
javascript 复制代码
submitForm(st) {
    const classData = this.classData
    const valid = (classData.name === 0 ||classData.name)  && (classData.sort === 0 || classData.sort)
    if (this.action === 'add') {
        if (valid) {
            const reg = /^\d+$/
            if (reg.test(classData.sort)) {
                addCategory({'name': classData.name,'type':this.type, sort: classData.sort}).then(res => {
                    console.log(res)
                    if (res.code === 1) {
                        this.$message.success('分类添加成功!')
                        if (!st) {
                            this.classData.dialogVisible = false
                        } else {
                            this.classData.name = ''
                            this.classData.sort = ''
                        }
                        this.handleQuery()
                    }
                }
          }
      }
  }

第二步: 服务端Controller接收页面提交的数据并通过Service调用Mapper操作数据库保存添加的菜品/套餐分类信息

数据模型

数据模型category表: id是主键,name字段表示分类名称是唯一的,type字段为1表示菜品分类,为2表示套餐分类

后端处理请求

第一步: 创建实体类Category,对于createUser和createTime等公共字段使用自动填充功能

java 复制代码
@Data
public class Category implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    //类型 1 菜品分类 2 套餐分类
    private Integer type;
    //分类名称
    private String name;
    //顺序
    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;
}

第二步: 创建Mapper接口CategoryMapper和Service接口CategoryService及其实现类CatrgoryServiceImpl

java 复制代码
@Mapper
public interface CategoryMapper extends BaseMapper<Category> {
}

public interface CategoryService extends IService<Category> {
}

@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
}

第三步: 在CategoryController控制层中编写控制器方法,将接收到的json数据添加到数据库中并响应一个成功的提示信息

java 复制代码
@Slf4j
@RestController
@RequestMapping("/category")
public class CategoryController {
    @Autowired
    private CategoryService categoryService;
    @PostMapping
    public Result<String> save(@RequestBody Category category) {
        log.info("category:{}", category);
        categoryService.save(category);
        return Result.success("新增分类成功");
    }
}

分页查询所有菜品/套餐分类

页面原型

第一步:用户点击分页管理按钮时携带分页查询的相关参数page(默认1)、pageSize(默认10)发送Ajax请求到服务端去查询菜品/套餐的分类信息

第二步: 服务端Controller接受到请求之后通过Service调用Mapper操作数据库查询相关的菜品/套餐信息

第三步: Controller将查询到的所有数据和分页信息响应给前端

第四步: 前端接收到后端响应的数据后,通过ElementUI的Table组件渲染到页面上

  • 页面加载完毕之后调用created钩子函数,在该钩子函数内又调用init函数进行初始化
javascript 复制代码
created() {
    this.init()
}
async init () {
    await getCategoryPage({'page': this.page, 'pageSize': this.pageSize}).then(res => {
        if (String(res.code) === '1') {
            //将服务端查询到的所有数据赋给tableData,然后就能看到了
            this.tableData = res.data.records
            this.counts = Number(res.data.total)
        } else {
            this.$message.error(res.msg || '操作失败')
        }
    }).catch(err => {
        this.$message.error('请求出错了:' + err)
    })
}
// 查询列表接口
const getCategoryPage = (params) => {
    return $axios({
        url: '/category/page',
        method: 'get',
        params
    })
}

后端处理请求

执行categoryService提供的page方法进行分页查询并将查询到的数据和分页信息响应给前端

java 复制代码
@GetMapping("/page")
public Result<Page> page(int page, int pageSize) {
    // 创建分页构造器
    Page<Category> pageInfo = new Page<>(page, pageSize);
    // 构造条件查询器
    LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
    // 添加排序条件,根据sort属性进行排序
    queryWrapper.orderByDesc(Category::getSort);
    // 执行分页查询的语句
    categoryService.page(pageInfo, queryWrapper);
    // 将查询到的所有数据和分页相关的信息响应给前端
    return Result.success(pageInfo);
}

删除某个分类(判断有无关联)

页面原型

第一步:在分类管理列表页面, 用户点击某个分类对应的删除按钮发送Ajax请求,请求参数就是该菜品/套餐分类单元格对应的属性Id

  • 删除是个危险的操作,当用户点击删除按钮时先给一个提示信息防止误操作,当用户点确定后才会执行deleCategory回调函数
html 复制代码
<el-button
           type="text"
           size="small"
           class="delBut non"
           <!--删除按钮绑定了deleteHandle函数,参数就是当前单元格的Id-->
		   @click="deleteHandle(scope.row.id)">
</el-button>
<script>
    deleteHandle(id) {
        this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
            'confirmButtonText': '确定',
            'cancelButtonText': '取消',
            'type': 'warning'
        }).then(() => {
            deleCategory(id).then(res => {
                // 服务端成功删除后提示'删除成功!'
                if (res.code === 1) {
                    this.$message.success('删除成功!')
                    this.handleQuery()
                } else {
                    this.$message.error(res.msg || '操作失败')
                }
            }).catch(err => {
                this.$message.error('请求出错了:' + err)
            })
        })
    }
    // 发其Ajax请求删除当前行
    const deleCategory = (id) => {
        return $axios({
            url: '/category',
            method: 'delete',
            params: {id}
        })
    }
</script>

第二步:服务端Controller接收页面提交的菜品/套餐分类的Id,通过Service调用Mapper根据Id删除对应的纪录,如果该分类关联了某个菜品或套餐时不允许被删除

后端处理请求(无关联)

java 复制代码
@DeleteMapping
private Result<String> delete(Long id) {
    log.info("将被删除的id:{}", id);
    categoryService.removeById(id);
    return Result.success("分类信息删除成功");
}

查询菜品/套餐

删除某个分类时需要先拿着当前分类的Id值去对应的菜品/套餐表中进行查询,如果能查询到数据则说明该分类关联了菜品/套餐,此时不能删除该分类

数据模型

套餐信息表setmeal

菜品信息表dish

后端处理请求

第一步: 创建菜品表和套餐表对应的模型类DishStemal,对于createUser和createTimecreateUser和updateUser等公共字段使用自动填充功能

java 复制代码
/**
 菜品
 */
@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;
}
java 复制代码
/**
 * 套餐
 */
@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;
}

第二步: 编写对应的Mapper接口和Service接口及其实现类

java 复制代码
@Mapper
public interface DishMapper extends BaseMapper<Dish> {
}

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

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

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

第三步: 在common包下新增CustomException异常类用于封装我们的自定义异常

java 复制代码
public class CustomException extends RuntimeException{
    public CustomException(String msg){
        super(msg);
    }
}

第四步: 在全局异常处理器中使用@ExceptionHandler注解专门处理CustomerException类型的异常

java 复制代码
@ExceptionHandler(CustomException.class)
public Result<String> exceptionHandler(CustomException exception) {
    log.error(exception.getMessage());
    return Result.error(exception.getMessage());
}

第五步: CategoryService接口中新增remove方法, 在删除数据之前先根据当前菜品/套餐分类的categoryId值去dish表和setmeal表中查询是否关联了数据

  • 如果查询到了数据: 说明存在关联的菜品/套餐数据即不能删除需要抛出一个自定义异常
  • 如果查询不到数据: 说明不存在关联的菜品/套餐数据那么可以正常删除
java 复制代码
@Service
@Slf4j
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
    @Autowired
    DishService dishService;
    @Autowired
    SetmealService setmealService;
    /**
     * 根据id删除分类,删除之前需要进行判断
     * @param id
     */
    @Override
    public void remove(Long id) {
        // 根据菜品的分类id去菜品表中查询关联的菜品记录
        LambdaQueryWrapper<Dish> dishLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishLambdaQueryWrapper.eq(Dish::getCategoryId, id);
        int count1 = dishService.count(dishLambdaQueryWrapper);
        // 判断菜品当前分类是否关联了菜品,如果已经关联则抛出异常
        if (count1 > 0){
            throw new CustomException("当前分类下关联了菜品,不能删除");
        }
        // 根据套餐的分类id去套餐表中查询关联的套餐记录
        LambdaQueryWrapper<Setmeal> setmealLambdaQueryWrapper = new LambdaQueryWrapper<>();
        setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
        // 判断当前套餐分类是否关联了套餐,如果已经关联则抛出异常
        int count2 = setmealService.count(setmealLambdaQueryWrapper);
        if (count2 > 0){
            throw new CustomException("当前分类下关联了套餐,不能删除");
        }
        // 没有关联菜品/套餐则调用CategoryService自带的removeById方法正常删除
        super.removeById(id);
    }
}

第六步: 在Controller中调用CategoryService新增的remove方法

java 复制代码
@DeleteMapping
public Result<String> delete(Long id){
    log.info("将要删除的分类id:{}",id);
    categoryService.remove(id);
    return Result.success("分类信息删除成功");
}

修改分类信息

页面原型

第一步: 用户在分类管理列表页面中点击修改"按钮后弹出修改窗口,此时会回显当前菜品/套餐分类的信息并等待用户修改(通过Vue的数据绑定功能实现自动回显)

html 复制代码
<el-button
           type="text"
           size="small"
           class="blueBug"
           <!--回显当前分类的信息,参数就是当前单元格的信息-->
			@click="editHandle(scope.row)"
>
修改
</el-button>

<el-form
         class="demo-form-inline"
         label-width="100px"
         >
    <el-form-item label="分类名称:">
        <el-input
                  v-model="classData.name"
                  placeholder="请输入分类名称"
                  maxlength="14"
                  />
    </el-form-item>
    <el-form-item label="排序:">
        <el-input v-model="classData.sort"  type="number" placeholder="请输入排序" />
    </el-form-item>
</el-form>

<script>
    editHandle(dat) {
        // 这里并没有从后端查数据进行回显,而是对Vue双向绑定的数据classData下的name和sort属性进行赋值实现回显效果
        this.classData.title = '修改分类'
        this.action = 'edit'
        this.classData.name = dat.name
        this.classData.sort = dat.sort
        this.classData.id = dat.id
        this.classData.dialogVisible = true
    }
    classData: {
        'title': '添加菜品分类',
         'dialogVisible': false,
         'categoryId': '',
         'name': '',
          sort: ''
    }
</script>

第二步: 用户点击确定按钮后执行通用的submitForm函数发起Ajax请求,以json格式提交修改后的菜品/套餐分类信息

html 复制代码
<script>
    submitForm(st) {
        const classData = this.classData
        const valid = (classData.name === 0 ||classData.name)  && (classData.sort === 0 || classData.sort)
        // 添加操作从这里执行
        if (this.action === 'add') {
            if (valid) {
                const reg = /^\d+$/
                if (reg.test(classData.sort)) {
                    addCategory({'name': classData.name,'type':this.type, sort: classData.sort}).then(res => {
                        console.log(res)
                        if (res.code === 1) {
                            this.$message.success('分类添加成功!')
                            if (!st) {
                                this.classData.dialogVisible = false
                            } else {
                                this.classData.name = ''
                                this.classData.sort = ''
                            }
                            this.handleQuery()
                        } else {
                            this.$message.error(res.msg || '操作失败')
                        }
                    }).catch(err => {
                        this.$message.error('请求出错了:' + err)
                    })
                } else {
                    this.$message.error('排序只能输入数字类型')
                }

            } else {
                this.$message.error('请输入分类名称或排序')
            }
        // 修改操作从这里执行
        } else if (valid) {
            const reg = /^\d+$/
            if (reg.test(this.classData.sort)) {
                // 发起ajax请求修改员工数据
                editCategory({'id':this.classData.id,'name': this.classData.name, sort: this.classData.sort}).then(res => {
                    if (res.code === 1) {
                        this.$message.success('分类修改成功!')
                        this.classData.dialogVisible = false
                        this.handleQuery()
                    } else {
                        this.$message.error(res.msg || '操作失败')
                    }
                }).catch(err => {
                    this.$message.error('请求出错了:' + err)
                })
            } else {
                this.$message.error('排序只能输入数字类型')
            }
        } else {
            this.$message.error('请输入分类名称或排序')
        }
    }
    // 修改接口
    const editCategory = (params) => {
        return $axios({
            url: '/category',
            method: 'put',
            data: { ...params }
        })
    }
</script>

后端处理请求

根据用户提交的json格式的菜品/套餐分类信息,去数据表中更新对应的菜品/套餐记录

java 复制代码
@PutMapping
public Result<String> update(@RequestBody Category category) {
    log.info("修改分类信息为:{}", category);
    categoryService.updateById(category);
    return Result.success("修改分类信息成功");
}
相关推荐
古月居GYH3 分钟前
在C++上实现反射用法
java·开发语言·c++
儿时可乖了1 小时前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
ruleslol1 小时前
java基础概念37:正则表达式2-爬虫
java
xmh-sxh-13141 小时前
jdk各个版本介绍
java
天天扭码1 小时前
五天SpringCloud计划——DAY2之单体架构和微服务架构的选择和转换原则
java·spring cloud·微服务·架构
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
FIN技术铺2 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小曲程序2 小时前
vue3 封装request请求
java·前端·typescript·vue