某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548
文章目录
- 1.需求分析
- 2.代码开发
- 2.1 执行过程分析
- 2.2 代码实现
- 2.2.1 准备实体类
- 2.2.2 准备 Mapper 接口
- 2.2.3 准备 Service 接口及实现类
- 2.2.4 自定义 remove 方法
- 3.功能测试
1.需求分析
在分类管理页面,可以对某个分类进行删除操作。但是需要注意的是,当分类关联了菜品或者套餐时,此分类不允许删除。
2.代码开发
2.1 执行过程分析
在开发代码之前,需要梳理一下整个程序的执行过程:
- 页面发送 ajax 请求,将参数(id)提交到服务端;
- 服务端 Controller 接收页面提交的数据并调用 Service 删除数据;
- Service 调用 Mapper 操作数据库。
下面同样简单看一下对应客户端发送的请求信息:
2.2 代码实现
注意,因为当分类关联了菜品或者套餐时,此分类不允许删除。因此,我们不能简单的调用 MyBatis Plus 提供的 categoryService.removeById(id)
方法直接进行删除。而是需要检查删除的分类是否关联了菜品或者套餐,因此我们需要进行一些功能上的扩展。
要完善分类删除功能,需要先准备基础的类和接口。首先需要实体类 Dish
和 Setmeal
,菜品和套餐这两个实体类在前面同意导入实体的时候已经导入了,直接使用即可。
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.功能测试
随便删除一个带有关联的分类进行删除操作:
新建一个没有关联的菜品分类:
删除新增的测试菜品,删除成功: