您现在的位置是:首页 >学无止境 >瑞吉外卖 - 新增菜品功能(16)网站首页学无止境
瑞吉外卖 - 新增菜品功能(16)
某马瑞吉外卖单体架构项目完整开发文档,基于 Spring Boot 2.7.11 + JDK 11。预计 5 月 20 日前更新完成,有需要的胖友记得一键三连,关注主页 “瑞吉外卖” 专栏获取最新文章。
相关资料:https://pan.baidu.com/s/1rO1Vytcp67mcw-PDe_7uIg?pwd=x548
提取码:x548
1.需求分析
后台系统中可以管理菜品信息,通过新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片,在移动端会按照菜品分类来展示对应的菜品信息。
2.数据模型
新增菜品,其实就是将新增页面录入的菜品信息插入到 dish 表,如果添加了口味做法,还需要向 dish_flavor 表插入数据。所以在新增菜品时,涉及以下两个表:
dish:菜品表
dish_flavor:菜品口味表
3.代码开发
3.1 搭建代码框架
在开发业务功能前,先将需要用到的类和接口基本结构创建好,流程与之前一样。
实体类 Dish
和 DishFlavor
直接从下载资料中导入即可,Dish
实体前面已经导入过了,DishFlavor
实体类完整代码如下:
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.time.LocalDateTime;
/**
* 菜品口味
*/
@Data
public class DishFlavor implements Serializable {
// 序列化版本号
private static final long serialVersionUID = 1L;
//主键
private Long id;
//菜品id
private Long dishId;
//口味名称
private String name;
//口味数据 list
private String value;
@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;
}
Mapper 接口 DishFlavorMapper
相关代码如下:
package cn.javgo.reggie_take_out.mapper;
import cn.javgo.reggie_take_out.entity.DishFlavor;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
}
业务层接口 DishFlavorService
相关代码如下:
package cn.javgo.reggie_take_out.service;
import cn.javgo.reggie_take_out.entity.DishFlavor;
import com.baomidou.mybatisplus.extension.service.IService;
public interface DishFlavorService extends IService<DishFlavor> {
}
业务层实现类 DishFlavorServicelmpl
相关代码如下:
package cn.javgo.reggie_take_out.service.impl;
import cn.javgo.reggie_take_out.entity.DishFlavor;
import cn.javgo.reggie_take_out.mapper.DishFlavorMapper;
import cn.javgo.reggie_take_out.service.DishFlavorService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class DishFlavorServicelmpl extends ServiceImpl<DishFlavorMapper, DishFlavor> implements DishFlavorService {
}
控制层 DishController
相关代码如下:
package cn.javgo.reggie_take_out.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 菜品控制器
*/
@RestController
@RequestMapping("/dish")
public class DishController {
@Resource
private DishService dishService;
@Resource
private DishFlavorService dishFlavorService;
@Resource
private CategoryService categoryService;
}
3.2 梳理交互过程
在开发代码之前,需要梳理一下新增菜品时前端页面和服务端的交互过程:
- 页面(backend/page/food/add.html)发送 ajax 请求,请求服务端获取菜品分类数据并展示到下拉框中;
- 页面发送请求进行图片上传,请求服务端将图片保存到服务器;
- 页面发送请求进行图片下载,将上传的图片进行回显;
- 点击保存按钮,发送 ajax 请求,将菜品相关数据以 json 形式提交到服务端。
开发新增菜品功能,其实就是在服务端编写代码去处理前端页面发送的这 4 次请求即可。
展示分类列表的请求:
上传图片的请求:(已实现)
下载图片的请求:(已实现)
保存菜品信息的请求:
3.3 代码实现
CategoryController
中对应的处理分类列表的方法如下:
@RestController
@RequestMapping("/category")
public class CategoryController {
/**
* 根据条件查询分类列表
* @param category 分类实体
* @return R
*/
@GetMapping("/list")
public R<List<Category>> list(Category category){
// 1.构造查询条件
QueryWrapper<Category> queryWrapper = new QueryWrapper<>();
// 2.添加查询条件(根据分类类型查询)
queryWrapper.eq("type",category.getType());
// 3.添加排序条件(先根据 sort 字段进行排序,再根据更新时间进行排序)
queryWrapper.orderByAsc("sort").orderByDesc("update_time");
// 4.执行查询
List<Category> list = categoryService.list(queryWrapper);
// 5.返回结果
return R.success(list);
}
// 省略其他方法
}
在开发处理保存菜品信息方法是我们需要先关注一个问题,方法参数直接封装为 Dish
吗?不妨我们先来看看在发送请求时都携带了哪些 json 数据:
从其中圈出的口味可以看出 json 数据中还携带了关于口味的信息,但是该属性在 Dish
实体类里面是没有的。这种情况下我们可以使用 DTO,全称为 Data Transfer Object,即数据传输对象,一般用于显示层与服务层之间的数据传输。对此我们可以提供一个 dto/DishDto.java
用于封装页面提交的数据。
资料位置:瑞吉外卖瑞吉外卖项目资料dto
该目录下有三个 Dto 类,我们可以一次全部复制到项目的 dto 目录下,以免后续重复导入。
完整代码如下:
package cn.javgo.reggie_take_out.dto;
import cn.javgo.reggie_take_out.entity.Dish;
import cn.javgo.reggie_take_out.entity.DishFlavor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class DishDto extends Dish {
// 菜品口味,接收前端传来的数据
private List<DishFlavor> flavors = new ArrayList<>();
// 菜品分类名称
private String categoryName;
private Integer copies;
}
其中的 flavors 属性就是用来处理请求携带的 json 数据中的 flavors 口味数据的,同时该类继承了 Dish
实体类,拥有 Dish
的属性。这样我们就可以在相应的处理方法中提供 DishDto
作为方法参数进行封装了。
DishController
中对应的处理保存菜品信息方法如下:
@RestController
@RequestMapping("/dish")
public class DishController {
@Resource
private DishService dishService;
/**
* 新增菜品
* @param dishDto 自定义的 DTO 对象,用于接收前端传递的数据
* @return R
*/
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
// 调用菜品业务层自定义的新增菜品方法
dishService.saveWithFlavor(dishDto);
return R.success("新增菜品成功");
}
// 省略其他方法
}
由于保存操作要同时操作 dish 和 dish_flavor 表两张表,因此我们需要自定义 saveWithFlavor
保存方法,DishService
中对应的抽象方法如下:
package cn.javgo.reggie_take_out.service;
import cn.javgo.reggie_take_out.dto.DishDto;
import cn.javgo.reggie_take_out.entity.Dish;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @author: JavGo
* @description: TODO
* @date: 2023/5/17 20:38
*/
public interface DishService extends IService<Dish> {
/**
* 新增菜品,同时新增菜品口味(需要操作两张表)
* @param dishDto 自定义的 DTO 对象,用于接收前端传递的数据
*/
public void saveWithFlavor(DishDto dishDto);
}
然后在 DishServiceImpl
中进行具体实现,完整代码如下:
package cn.javgo.reggie_take_out.service.impl;
import cn.javgo.reggie_take_out.dto.DishDto;
import cn.javgo.reggie_take_out.entity.Dish;
import cn.javgo.reggie_take_out.entity.DishFlavor;
import cn.javgo.reggie_take_out.mapper.DishMapper;
import cn.javgo.reggie_take_out.service.DishFlavorService;
import cn.javgo.reggie_take_out.service.DishService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author: JavGo
* @description: TODO
* @date: 2023/5/17 20:39
*/
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
@Resource
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时新增菜品口味(需要操作两张表)
* @param dishDto 自定义的 DTO 对象,用于接收前端传递的数据
*/
@Transactional
@Override
public void saveWithFlavor(DishDto dishDto) {
// 1.保存菜品的基本信息到菜品表
this.save(dishDto);
// 2.获取菜品的 id
Long dishId = dishDto.getId();
// 3.获取菜品口味
List<DishFlavor> flavors = dishDto.getFlavors();
// 4.遍历菜品口味,设置菜品 id
flavors.forEach(flavor -> flavor.setDishId(dishId));
// 5.批量保存菜品口味
dishFlavorService.saveBatch(flavors);
}
}
4.功能测试
重启应用,进行新建菜品功能测试:
查看数据库,添加成功: