新增菜品/套餐分类
页面原型
当我们在后台系统中添加菜品/套餐
时,需要选择一个菜品/套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐
第一步: 用户点击确定按钮
执行submitForm
函数发送Ajax请求,将新增菜品/套餐
表单中输入的数据以json形式提交给服务端,等待服务端响应数据后执行回调函数
<!--用户在表单页面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>
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
等公共字段使用自动填充
功能
@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
@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数据添加到数据库中并响应一个成功的提示信息
@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函数
进行初始化
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
方法进行分页查询并将查询到的数据和分页信息响应给前端
@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回调函数
<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
删除对应的纪录,如果该分类关联了某个菜品或套餐时不允许被删除
后端处理请求(无关联)
@DeleteMapping
private Result<String> delete(Long id) {
log.info("将被删除的id:{}", id);
categoryService.removeById(id);
return Result.success("分类信息删除成功");
}
查询菜品/套餐
删除某个分类时需要先拿着当前分类的Id
值去对应的菜品/套餐表
中进行查询,如果能查询到数据则说明该分类关联了菜品/套餐,此时不能删除该分类
数据模型
套餐信息表setmeal
菜品信息表dish
后端处理请求
第一步: 创建菜品表和套餐表对应的模型类Dish
和Stemal
,对于createUser和createTime
和createUser和updateUser
等公共字段使用自动填充
功能
/**
菜品
*/
@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;
}
/**
* 套餐
*/
@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接口及其实现类
@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
异常类用于封装我们的自定义异常
public class CustomException extends RuntimeException{
public CustomException(String msg){
super(msg);
}
}
第四步: 在全局异常处理器中使用@ExceptionHandler注解
专门处理CustomerException
类型的异常
@ExceptionHandler(CustomException.class)
public Result<String> exceptionHandler(CustomException exception) {
log.error(exception.getMessage());
return Result.error(exception.getMessage());
}
第五步: CategoryService
接口中新增remove
方法, 在删除数据之前先根据当前菜品/套餐分类的categoryId
值去dish表和setmeal表
中查询是否关联了数据
如果查询到了数据
: 说明存在关联的菜品/套餐数据即不能删除需要抛出一个自定义异常如果查询不到数据
: 说明不存在关联的菜品/套餐数据那么可以正常删除
@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方法
@DeleteMapping
public Result<String> delete(Long id){
log.info("将要删除的分类id:{}",id);
categoryService.remove(id);
return Result.success("分类信息删除成功");
}
修改分类信息
页面原型
第一步: 用户在分类管理列表页面中点击修改"按钮
后弹出修改窗口,此时会回显当前菜品/套餐分类的信息并等待用户修改(通过Vue的数据绑定功能实现自动回显)
<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格式提交修改后的菜品/套餐分类信息
<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格式的菜品/套餐分类信息
,去数据表中更新对应的菜品/套餐记录
@PutMapping
public Result<String> update(@RequestBody Category category) {
log.info("修改分类信息为:{}", category);
categoryService.updateById(category);
return Result.success("修改分类信息成功");
}