在分类管理列表页面,可以对某个分类进行删除操作。需要注意的是当分类关联了菜品或者套餐时,此分类不允许删除。
在前端页面中,点击 "删除" 按钮,就会触发定义的方法,然后往服务端发送异步请求,并传递参数id,执行删除分类操作。
删除操作的具体执行流程如下:
1). 点击删除,页面发送ajax请求,将参数(id)提交到服务端
2). 服务端Controller接收页面提交的数据并调用Service删除数据
3). Service调用Mapper操作数据库
从上述的分析中,可以得到请求的信息如下:
请求 | 说明 |
---|---|
请求方式 | DELETE |
请求路径 | /category |
请求参数 | ?id=1395291114922618881 |
删除分类数据需要检查删除的分类是否关联了菜品或者套餐,所以需要进行功能完善。完善后的逻辑为:
根据当前分类的ID,查询该分类下是否存在菜品,如果存在,则提示错误信息
根据当前分类的ID,查询该分类下是否存在套餐,如果存在,则提示错误信息
执行正常的删除分类操作
那么在这里又涉及到两张表结构 dish(菜品表) 和 setmeal(套餐表)。具体的表结构如下:
1.4.1 Dish菜品实体类
- package com.itheima.reggie.entity;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.IdType;
- import com.baomidou.mybatisplus.annotation.TableField;
- import com.baomidou.mybatisplus.annotation.TableId;
- 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;
-
- }
- package com.itheima.reggie.entity;
-
- import com.baomidou.mybatisplus.annotation.FieldFill;
- import com.baomidou.mybatisplus.annotation.IdType;
- import com.baomidou.mybatisplus.annotation.TableField;
- import com.baomidou.mybatisplus.annotation.TableId;
- 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;
-
- }
1.4.3. Mapper接口DishMapper和SetmealMapper
DishMapper
- package com.itheima.reggie.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.itheima.reggie.entity.Dish;
- import org.apache.ibatis.annotations.Mapper;
-
- @Mapper
- public interface DishMapper extends BaseMapper
{ - }
SetmealMapper
- package com.itheima.reggie.mapper;
-
- import com.baomidou.mybatisplus.core.mapper.BaseMapper;
- import com.itheima.reggie.entity.Setmeal;
- import org.apache.ibatis.annotations.Mapper;
-
- @Mapper
- public interface SetmealMapper extends BaseMapper
{ - }
DishService
- package com.itheima.reggie.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.itheima.reggie.entity.Dish;
-
- public interface DishService extends IService
{ - }
SetmealService
- package com.itheima.reggie.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.itheima.reggie.entity.Setmeal;
-
- public interface SetmealService extends IService
{ - }
在业务逻辑操作过程中,如果遇到一些业务参数、操作异常的情况下,直接抛出此异常。
- package com.itheima.reggie.common;
-
- import javax.xml.crypto.dsig.spec.XSLTTransformParameterSpec;
-
- /**
- * Description: 自定义业务异常类
- * @date 2022/8/16 10:32
- */
- public class CustomException extends RuntimeException{
- public CustomException(String message){
- super(message);
- }
- }
2). 在CategoryService中扩展remove方法
- package com.itheima.reggie.service;
-
- import com.baomidou.mybatisplus.extension.service.IService;
- import com.itheima.reggie.entity.Category;
-
- public interface CategoryService extends IService
{ - public void remove(Long id);
- }
3). 在CategoryServiceImpl中实现remove方法
- package com.itheima.reggie.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.itheima.reggie.common.CustomException;
- import com.itheima.reggie.entity.Category;
- import com.itheima.reggie.entity.Dish;
- import com.itheima.reggie.entity.Setmeal;
- import com.itheima.reggie.mapper.CategoryMapper;
- import com.itheima.reggie.service.CategoryService;
- import com.itheima.reggie.service.DishService;
- import com.itheima.reggie.service.SetmealService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
-
- /**
- * Description: 类别业务层接口
- * @version 1.0
- * @date 2022/8/15 13:55
- */
-
- @Service
- public class CategoryServiceImpl extends ServiceImpl
implements CategoryService { -
- @Autowired
- private DishService dishService ;
- @Autowired
- private SetmealService setmealService;
-
-
-
- @Override
- /**@Description: 根据id删除分类,删除之前需要判定是否关联菜品
- * @version v1.0
- * @author LiBiGo
- * @date 2022/8/16 10:20
- */
- public void remove(Long id) {
-
- // A.查询当前分类是否关联菜品,关联则抛出业务异常类
- LambdaQueryWrapper
dishLambdaQueryWrapper = new LambdaQueryWrapper<>(); - // 添加查询条件,根据id查询
- dishLambdaQueryWrapper.eq(Dish::getCategoryId,id);
- int count1 = dishService.count(dishLambdaQueryWrapper);
-
- if (count1 > 0){
- // 已关联菜品,抛出异常
- throw new CustomException("当前分类下关联了菜品,不能删除");
- }
-
- // B.查询当前分类是否关联套餐,关联则抛出业务异常类
- LambdaQueryWrapper
setmealLambdaQueryWrapper = new LambdaQueryWrapper<>(); - // 添加查询条件,根据id查询
- setmealLambdaQueryWrapper.eq(Setmeal::getCategoryId,id);
- int count2 = setmealService.count(setmealLambdaQueryWrapper);
- if (count2 > 0){
- // 已关联套餐,抛出异常
- throw new CustomException("当前分类下关联了套餐,不能删除");
- }
-
- // 均无关联,则删除
- super.removeById(id); // 父类实现了最基本的根据id查询的删除,所以直接调用就行
- }
- }
那么在上述的业务逻辑中,当分类下关联的有菜品或者套餐时,在业务代码中抛出了自定义异常,会被异常处理器捕获,只需要在异常处理器中捕获这一类的异常,然后给页面返回对应的提示信息即可。
4). 在GlobalExceptionHandler中处理自定义异常
在全局异常处理器中增加方法,用于捕获自定义的异常 CustomException
- package com.itheima.reggie.common;
-
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Controller;
- import org.springframework.web.bind.annotation.ControllerAdvice;
- import org.springframework.web.bind.annotation.ExceptionHandler;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.bind.annotation.RestController;
- import java.sql.SQLIntegrityConstraintViolationException;
- /**
- * Description: 全局异常处理器
- */
-
- @ControllerAdvice(annotations = {RestController.class, Controller.class})// 处理@RestController、@Controller的函数异常 //指定拦截那些类型的控制器;
- @ResponseBody //将方法的返回值 R 对象转换为json格式的数据, 响应给页面;
- @Slf4j
- public class GlobalExceptionHandler {
-
- /**@Description: 异常处理方法
- * @author LiBiGo
- * @date 2022/8/12 17:46
- */
- @ExceptionHandler(SQLIntegrityConstraintViolationException.class) // 处理指定异常类
- public R
exceptionHandler(SQLIntegrityConstraintViolationException ex){ - log.error(ex.getMessage());
- //Duplicate entry '299067' for key 'idx_username'
- if(ex.getMessage().contains("Duplicate entry")){
- String[] split = ex.getMessage().split(" "); //提取重复字段,即哪个用户名重复 从0开始第2个即为用户名
- String msg = split[2] + "已存在";
- return R.error(msg);
- }
- return R.error("未知错误");
- }
-
- @ExceptionHandler(CustomException.class) // 处理自定义业务异常类
- public R
exceptionHandler(CustomException ex){ - log.error(ex.getMessage());
- return R.error(ex.getMessage());
- }
-
-
- }
5). 改造CategoryController的delete方法
注释掉原有的代码,在delete方法中直接调用categoryService中自定义的remove方法。
- package com.itheima.reggie.controller;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.itheima.reggie.common.R;
- import com.itheima.reggie.entity.Category;
- import com.itheima.reggie.service.CategoryService;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
-
- /**
- * Description: 分类管理
- */
-
- @RestController
- @RequestMapping("/category")
- @Slf4j
- public class CategoryController {
-
- @Autowired
- private CategoryService categoryService;
-
-
- /**@Description: 新增分类
- * @author LiBiGo
- * @date 2022/8/15 14:05
- */
- @PostMapping
- public R
save(@RequestBody Category category){ - log.info("category:{}",category);
- categoryService.save(category);
- return R.success("新增分类成功");
- }
-
-
- @GetMapping("/page")
- public R
page(int page,int pageSize){ - /**@Description: 分页查询
- * @author LiBiGo
- * @date 2022/8/15 14:21
- */
- // 分页构造
- Page
pageinfo = new Page<>(page,pageSize); - // 构造条件构造器对象
- LambdaQueryWrapper
queryWrapper = new LambdaQueryWrapper(); - // 添加排序条件,根据sore进行排序
- queryWrapper.orderByAsc(Category::getSort);
- // 进行分页查询
- categoryService.page(pageinfo,queryWrapper);
-
- return R.success(pageinfo);
- }
-
- @DeleteMapping
- public R
delete(Long id){ - /**@Description: 根据id删除分类
- * @author LiBiGo
- * @date 2022/8/16 9:58
- */
- log.info("删除分类,id为{}",id);
-
- categoryService.remove(id);
- return R.success("分类信息删除成功");
-
- }
-
- @PutMapping
- public R
update(@RequestBody Category category){ - /**@Description: 根据id修改分类信息
- * @author LiBiGo
- * @date 2022/8/16 10:49
- */
- log.info("根据id修改分类信息:{}",category);
- categoryService.updateById(category);
- return R.success("修改分类成功");
- }
- }
在分类管理列表页面点击修改按钮,弹出修改窗口,在修改窗口回显分类信息并进行修改,最后点击确定按钮完成修改操作。
这里面大家会发现,修改功能我们还没有实现,但是当点击 "修改" 按钮的时候,我们并没有开发根据ID查询数据,进行页面回显的功能,但是页面的分类数据确实回显回来了。这是怎么做到的呢,我们来解析一下前端的代码实现(前端代码已经实现):
那么回显这一步的操作前端已经实现,我们就只需要开发一个方法,修改操作的方法即可。我们可以通过浏览器来抓取一下修改操作的请求信息,如图:
具体的请求信息,整理如下:
请求 | 说明 |
---|---|
请求方式 | PUT |
请求路径 | /category |
请求参数 | {id: "1399923597874081794", name: "超值午餐", sort: 0} |
html页面中相关的代码都已经提供好了,我们已经分析了请求的信息,接下来就可以来创建服务端的CategoryController方法update方法。
【见上一个代码块,已集成】