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("修改分类信息成功");
}
相关推荐
李慕婉学姐7 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆9 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin9 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model20059 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉9 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国10 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824810 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈10 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9910 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹10 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理