A complete development document of a Ma Ruiji takeaway single architecture project, based on Spring Boot 2.7.11 + JDK 11. It is expected that the update will be completed before May 20th. Fat friends in need should remember to click three times, and pay attention to the homepage "St. Regis Takeaway" column to get the latest articles.
Related information: https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
Extraction code: x548
Article Directory
1. Demand analysis
On the category management page, you can delete a category. However, it should be noted that when a category is associated with a dish or set meal, this category cannot be deleted.
2. Code development
2.1 Perform process analysis
Before developing the code, you need to sort out the execution process of the entire program:
- The page sends an ajax request and submits the parameter (id) to the server;
- The server-side Controller receives the data submitted by the page and calls the Service to delete the data;
- Service calls Mapper to operate the database.
Let's also briefly look at the request information sent by the corresponding client:
2.2 Code implementation
Note, because when a category is associated with dishes or set meals, this category cannot be deleted. Therefore, we cannot simply call categoryService.removeById(id)
the method provided by MyBatis Plus to delete directly. Instead, we need to check whether the deleted category is associated with dishes or set meals, so we need to expand some functions.
To improve the category deletion function, you need to prepare basic classes and interfaces first. First of all, the entity class Dish
and Setmeal
, the two entity classes of dish and set meal have been imported when the entity was agreed to be imported, and can be used directly.
2.2.1 Prepare Entity Classes
entity/Dish.java
The complete code of the entity class is as follows:
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
The complete code of the entity class is as follows:
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 Prepare the Mapper interface
The corresponding mapper/DishMapper.java
interface is as follows:
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> {
}
The corresponding mapper/SetmealMapper.java
interface is as follows:
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 Prepare Service interface and implementation class
The corresponding service/DishService.java
interface is as follows:
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> {
}
The corresponding service/impl/DishServiceImpl.java
implementation class is as follows:
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 {
}
The corresponding service/SetmealService.java
interface is as follows:
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> {
}
The corresponding service/impl/SetmealServiceImpl.java
implementation class is as follows:
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 Custom remove method
To implement our checking logic, we cannot use the ready-made method provided by MyBatis Plus, we need to CategoryService
customize it in the interface:
public interface CategoryService extends IService<Category> {
/**
* 删除分类
* @param id 分类id
*/
public void remove(Long id);
}
CategoryServiceImpl
Then implement the abstract method in the implementation of the interface :
@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
The custom business exceptions involved in the above code are as follows:
package cn.javgo.reggie_take_out.common;
/**
* 自定义业务异常
*/
public class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
}
handler/GlobalExceptionHandler.java
At the same time, we also need to handle the custom exception in our global exception handler:
@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());
}
// 省略其他方法
}
Finally, CategoryController
write the corresponding processing method in :
@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. Functional test
Randomly delete a category with an association to delete:
Create a new unassociated dish category:
Delete the newly added test dish, the deletion is successful: