菜品管理业务开发

您所在的位置:网站首页 上传文件过程修改了文件名 菜品管理业务开发

菜品管理业务开发

2023-06-20 07:27| 来源: 网络整理| 查看: 265

1. 文件的上传下载  4-2

这里解释文件的上传时上传到我们后端指定的路径,下载时下到前端页面去

1.1 文件上传介绍  4-2

文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。

文件上传时,对页面的form表单有如下要求:

●method="post" 采用post方式提交数据

●enctype="multipart/ form-data" 采用multipart格式上传文件

●type="file" 使用input的file控件.上传

举例:

菜品管理业务开发_服务端

1.1.1 服务端文件上传   4-2

服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件:

●commons-fileupload

● commons-io

Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件,例如:

菜品管理业务开发_文件上传_02

1.2 文件下载介绍  4-2

文件下载,也称为download,是指将文件从服务器传输到本地计算机的过程。

通过浏览器进行文件下载,通常有两种表现形式:

● 以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录

●直接在浏览器中打开

通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程。

2. 文件上传代码实现  4-3

文件上传,页面端可以使用ElementUl提供的上传组件。

可以直接使用资料中提供的上传页面,位置

E:\java学习\瑞吉外卖\资料\1 瑞吉外卖项目\资料\文件上传下载页面

菜品管理业务开发_文件上传_03

菜品管理业务开发_spring_04

启动项目测试访问一下(这是没有写Controller类呢)

http://localhost:8080/backend/page/demo/upload.html

菜品管理业务开发_服务端_05

完成功能

文件上传和下载的控制器类CommonController  4-3package com.itheima.reggie.controller; import com.itheima.reggie.common.R; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; //专门负责我们的文件上传和下载的控制器类 4-3 @RestController @RequestMapping("/common") @Slf4j public class CommonController { //文件上传 4-3 @PostMapping("/upload") public R upload(MultipartFile file){ //file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除 log.info(file.toString()); return null; } }

这里测试要先登录,在去访问http://localhost:8080/backend/page/demo/upload.html

然后上传图片,才可使我们的file形参拿到图片资源(解释为什么,肯定有疑问不可以直接访问http://localhost:8080/backend/page/demo/upload.html吗,因为我们的demo/upload.html也是放在backend目录下的呀,而且backend目录还是被我们指定了静态资源路径映射的直接访问不就行了,其实这么理解是完全错误的,我们的目的是让我们的Controller类拿到图片资源(其实就是访问common/upload路径)而不是访问它(upload.html页面),应为我们设置过滤器的所以当我们访问上述路径添加图片时会访问common/upload路径(这个upload路径就是我们的Controller类upload方法上的,所以你要访问这个,就必须过过滤器这一关) 但是 这个路径在过滤器中会被拦截(因为只有过滤器中放行的路径可以通过,具体参考过滤器代码),所以我们就无法让我们的Controller类拿到图片资源

菜品管理业务开发_spring_06

菜品管理业务开发_spring_07

菜品管理业务开发_spring_08

2.1  指定临时文件转存  4-4

因为我们去添加图片每次都要先登录,在访问路径,在添加巴拉巴拉,很麻烦,所以重点我们直接在过滤器中设置放行common/upload路径(再次强调我们的目的是让Controller拿到图片资源,而不是访问它所以肯定要放行/common/**路径)

//定义不需要处理的请求路径 2-3 String[] urls = new String[]{ "/employee/login", "/employee/logout", "/backend/**", "/front/**", "/common/**" };application.properties#配置文件下载的路径 4-4 reggie: path: E:\java\ruijiwaimai_download_picture_temp\

测试随机生成文件名 在test中测试

UploadFileTest

package com.itheima.test; import org.junit.jupiter.api.Test; public class UploadFileTest { //测试随机生成的文件名 4-4 @Test public void test1(){ String fileName = "ererewe.jpg"; String suffix = fileName.substring(fileName.lastIndexOf(".")); System.out.println(suffix); } }

没问题

菜品管理业务开发_文件上传_09

继续完善文件上传功能CommonController    4-4package com.itheima.reggie.controller; import com.itheima.reggie.common.R; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; //专门负责我们的文件上传和下载的控制器类 4-3 @RestController @RequestMapping("/common") @Slf4j public class CommonController { //动态注入文件下载路径 4-4 @Value("${reggie.path}") private String basePath; //文件上传 4-3 @PostMapping("/upload") public R upload(MultipartFile file){ //file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除 log.info(file.toString()); //原始文件名 String originalFilename = file.getOriginalFilename();//xx.jpg //截取原始文件名后缀 String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); //使用UUID随机重新生成文件名,防止文件名称重复造成文件覆盖 String fileName = UUID.randomUUID().toString()+suffix; //创建一个目录对象 4-4 File dir = new File(basePath); //判断当前目录是否存在 if(!dir.exists()){ //目录不存在,需要创建 dir.mkdirs(); } try { //将临时文件转存到指定位置 4-4 file.transferTo(new File(basePath + originalFilename)); } catch (IOException e) { e.printStackTrace(); } return R.success(fileName); } }

访问http://localhost:8080/backend/page/demo/upload.html添加图片 临时文件转存成功

菜品管理业务开发_spring_10

3. 文件的下载  4-5

温馨提示,输入流是读文件将一个文件读到一个数组中,输出流是写文件将文件从一个数组写到浏览器

菜品管理业务开发_文件上传_11

//文件下载 4-5 @GetMapping("/download") public void download(String name, HttpServletResponse response){//这里这个name我们是从上传方法中返回给前端的 try { //输入流,通过输入流读取到文件内容 //basePath + name组合起来的是我们保存文件的路径 FileInputStream fileInputStream = new FileInputStream(new File(basePath + name)); //输出流,通过输出流将文件写回浏览器,在浏览器展示图片了 ServletOutputStream outputStream = response.getOutputStream(); //设置响应给浏览器是什么类型的资源,这里我们设置成图片资源 response.setContentType("image/jpeg"); int len = 0; byte[] bytes = new byte[1024];//定义一个数组 //使用输入流来读文件读到bytes数组中,只要不得-1就一直读,为-1就代表读完了 while ((len = fileInputStream.read(bytes)) != -1){ //受用输出流来写到浏览器,从bytes数组中来写 outputStream.write(bytes,0,len); outputStream.flush();//刷新一下 } //关闭资源 outputStream.close(); fileInputStream.close(); } catch (Exception e) { e.printStackTrace(); } }

菜品管理业务开发_文件上传_12

4. 新增菜品  4-64.1 需求分析  4-6

后台系统中可以管理菜品信息,通过新增功能来添加一个新的菜品,在添加菜品时需要选择当前菜品所属的菜品分类,并且需要上传菜品图片,在移动端会按照菜品分类来展示对应的菜品信息。

菜品管理业务开发_文件上传_13

4.2 数据模型  4-6

新增菜品,其实就是将新增页面录入的菜品信息插入到dish表,如果添加了口味做法,还需要向dish_ flavor表插入数据。

所以在新增菜品时,涉及到两个表:

●dish  菜品表

●dish_ flavor   菜品口味表

dish表

菜品管理业务开发_服务端_14

dish_ flavor表

菜品管理业务开发_服务端_15

4.3 代码开发  4-7

在开发业务功能前,先将需要用到的类和接口基本结构创建好:

●实体类DishFlavor (直接从课程资料中导入即可,Dish实体前面课程中已经导入过了)

●Mapper接口 DishFlavorMapper

业务层接口DishFlavorService

●业务层实现类DishFlavorServicelmpl

●控制层DishController

菜品管理业务开发_文件上传_16

菜品口味DishFlavor

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.time.LocalDateTime; /** 菜品口味 4-7 */ @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; }

菜品口味 持久层接口 DishFlavorMapper

package com.itheima.reggie.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.itheima.reggie.entity.DishFlavor; import org.apache.ibatis.annotations.Mapper; //菜品口味 持久层接口 4-7 @Mapper public interface DishFlavorMapper extends BaseMapper { }

菜品口味 业务层接口DishFlavorService

package com.itheima.reggie.service; import com.baomidou.mybatisplus.extension.service.IService; import com.itheima.reggie.entity.DishFlavor; //菜品口味 业务层接口 4-7 public interface DishFlavorService extends IService { }

菜品口味 业务层接口实现类DishFlavorServiceImpl

package com.itheima.reggie.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.reggie.entity.DishFlavor; import com.itheima.reggie.mapper.DishFlavorMapper; import com.itheima.reggie.service.DishFlavorService; import org.springframework.stereotype.Service; //菜品口味 业务层接口实现类 4-7 @Service public class DishFlavorServiceImpl extends ServiceImpl implements DishFlavorService { } 4.4 新增菜品功能开发  4-7

代码开发梳理交互过程

在开发代码之前,需要梳理一下新增菜品时前端页面和服务端的交互过程:

1.页面(backend/page/food/add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中

2、页面发送请求进行图片上传,请求服务端将图片保存到服务器

3、页面发送请求进行图片下载,将上传的图片进行回显

4、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端

开发新增菜品功能,其实就是在服务端编写代码去处理前端页面发送的这4次请求即可。

第一步   4-8

1.页面(backend/page/food/add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中

菜品管理业务开发_服务端_17

菜品管理业务开发_spring_18

CategoryController   根据条件查询分类数据   4-8/** * 根据条件查询分类数据 4-8 * @param category * @return */ @GetMapping("/list") public R list(Category category){ //条件构造器 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); //添加条件 queryWrapper.eq(category.getType() != null,Category::getType,category.getType()); //添加排序条件 queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime); List list = categoryService.list(queryWrapper); return R.success(list); }

菜品管理业务开发_spring_19

第二三步2、页面发送请求进行图片上传,请求服务端将图片保存到服务器 3、页面发送请求进行图片下载,将上传的图片进行回显

 我们已经在上面实现了

第四步  4-104、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端

菜品管理业务开发_服务端_20

菜品管理业务开发_服务端_21

因为上图可知前端传来的数据既有dish表的还有dish_flavors表的,所以我们不能简单的只用dish实体来接收,需要导入DTO

菜品管理业务开发_文件上传_22

导入DTO 资料路径E:\java学习\瑞吉外卖\资料\1 瑞吉外卖项目\资料\dto

菜品管理业务开发_spring_23

数据传输对象 DishDtopackage com.itheima.reggie.dto; import com.itheima.reggie.entity.Dish; import com.itheima.reggie.entity.DishFlavor; import lombok.Data; import java.util.ArrayList; import java.util.List; //数据传输对象DTO 4-9 @Data public class DishDto extends Dish { private List flavors = new ArrayList(); private String categoryName; private Integer copies; }

debug,发现口味表中的dishId并没有赋值只是name和value赋值了,这个重点,在我们将数保存到数据库时要注意

菜品管理业务开发_服务端_24

菜品管理业务层接口实现类 DishServiceImpl

我们在DishServiceImpl业务层中自己实现数据保存(因为涉及两张表操作框架无法为我们提供合适的方法)

package com.itheima.reggie.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.itheima.reggie.dto.DishDto; import com.itheima.reggie.entity.Dish; import com.itheima.reggie.entity.DishFlavor; import com.itheima.reggie.mapper.DishMapper; import com.itheima.reggie.service.DishFlavorService; import com.itheima.reggie.service.DishService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; //菜品管理业务层接口实现类 3-8 @Service @Slf4j public class DishServiceImpl extends ServiceImpl implements DishService { @Autowired private DishFlavorService dishFlavorService; //新增菜品,同时保存对应的口味数据 4-10 @Transactional //控制事务 4-10 public void saveWithFlavor(DishDto dishDto) { //保存菜品的基本信息到菜品表dish this.save(dishDto); //解释为什么还要设置菜品id,因为我们在保存菜品口味表dish_flavor时,是没有保存菜品id的 //原因在于,我们用的是数据传输对象DTO而DishDto没有做保存dishId(在我们通过debug时 // 发现的)所以我们需要对DishDto中封装的Flavors做一些改动,首先遍历 // 我们通过dishDto.getFlavors()得到DishDto中封装的Flavors集合,然后取出集合中的 //元素(也就是Flavors对象),给他们的dishId赋值,结束后在在将其封装成list集合 // (因为我们改了原来集合,需要将改变了dishId属性的Flavors对象也添加进list集合) //获取菜品id Long dishId = dishDto.getId(); //得到集合 List flavors = dishDto.getFlavors(); //遍历集合 //.stream()是将集合转化为流,.map是将流中的元素计算或者转换(此处用map是为流中的 // dishId赋值) .collect是将流转化为集合 flavors = flavors.stream().map((item)->{ item.setDishId(dishId); return item; }).collect(Collectors.toList());//.collect(Collectors.toList())改成list集合 //保存菜品口味数据到菜品口味表dish_flavor dishFlavorService.saveBatch(flavors); } }

是事务起作用

菜品管理业务开发_服务端_25

菜品管理 DishControllerpackage com.itheima.reggie.controller; import com.itheima.reggie.common.R; import com.itheima.reggie.dto.DishDto; import com.itheima.reggie.service.DishFlavorService; import com.itheima.reggie.service.DishService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; //菜品管理 4-7 @RestController @RequestMapping("/dish") @Slf4j public class DishController { @Autowired private DishService dishService; @Autowired private DishFlavorService dishFlavorService; /** * 新增菜品 4-9 4-10 * @param dishDto * @return */ @PostMapping public R save(@RequestBody DishDto dishDto){ log.info(dishDto.toString()); //调用我们自己在DishServiceImpl实现的方法 4-11 //我们在DishServiceImpl业务层中自己实现数据保存(因为涉及两张 // 表操作框架无法为我们提供合适的方法) dishService.saveWithFlavor(dishDto); return R.success("新增菜品成功"); } }

测试成功  4-11

菜品管理业务开发_文件上传_26

菜品表dish

菜品管理业务开发_服务端_27

口味表dish_flavor

菜品管理业务开发_文件上传_28

5. 菜品信息分页查询  4-125.1 需求分析  4-12

菜品管理业务开发_spring_29

5.2 代码开发-梳理交互过程  4-13

在开发代码之前,需要梳理一下菜品分页查询时前端页面和服务端的交互过程:

1、页面(backend/ page/food/list.html)发送ajax请求,将分页查询参数(page、pageSize、 name)提交到服务端,获取分页数据

2、页面发送请求,请求服务端进行图片下载,用于页面图片展示

开发菜品信息分页查询功能,其实就是在服务端编写代码去处理前端页面发送的这2次请求即可。

//菜品分页查询 4-13 @GetMapping("/page") public R page(int page,int pageSize,String name){ log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name); //构造分页构造器 //泛型只简单的使用Dish是不行的,因为没办法把菜品分类名称展示出来,所以还需要数据传输对象DTO 4-14 Page pageInfo = new Page(page, pageSize); //构造条件构造器 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); //添加过滤条件 queryWrapper.like(name!=null,Dish::getName,name); //添加排序条件 queryWrapper.orderByDesc(Dish::getUpdateTime); //执行分页查询 //这条语句会将我们查询到的数据进行封装 全部封装进Page的对象pageInfo dishService.page(pageInfo,queryWrapper); return R.success(dishDtoPage); }

菜品管理业务开发_spring_30

前端需要的数据

菜品管理业务开发_文件上传_31

后端响应的数据

菜品管理业务开发_文件上传_32

小提示  (这块相对复杂不明白就看视频) 4-14

由结果可以看出,我们的菜品分类名称并没有展示出来,这是为什么呢?因为前端需要的是菜品分 类name属性,而我们后端给他传过去的是菜品分类的id,原因就在于我们用的是dish作为泛型来接收(Page dishDtoPage = new Page(); 

重点的我们的目的就是得到一个泛型为DishDto的Page对象即dishDtoPage

图解

菜品管理业务开发_文件上传_33

代码实现  4-14

首先声明注入CategoryService属性

菜品管理业务开发_spring_34

DishController

//菜品分页查询 4-13 @GetMapping("/page") public R page(int page,int pageSize,String name){ log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name); //构造分页构造器 //泛型只简单的使用Dish是不行的,因为没办法把菜品分类名称展示出来,所以还需要数据传输对象DTO 4-14 Page pageInfo = new Page(page, pageSize); Page dishDtoPage = new Page(); //构造条件构造器 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); //添加过滤条件 queryWrapper.like(name!=null,Dish::getName,name); //添加排序条件 queryWrapper.orderByDesc(Dish::getUpdateTime); //执行分页查询 //这条语句会将我们查询到的数据进行封装 全部封装进Page的对象pageInfo dishService.page(pageInfo,queryWrapper); /* 解释 由结果可以看出,我们的菜品分类名称并没有展示出来,这是为什么呢?因为前端需要的是菜品分 类name属性,而我们后端给他传过去的是菜品分类的id,原因就在于我们用的是dish作为泛型来 接收(Page pageInfo = new Page(page, pageSize);),而dish里面没 有name属性,但是dishdto里面由categoryName属性,所以我们在 写一个Page dishDtoPage = new Page(); 重点的我们的目的就是得到一个泛型为DishDto的Page对象即dishDtoPage 需要将pageInfo拷贝给dishDtoPage但是但是不拷贝"records" 属性 因为这个records对 应的泛型是dish而我们需要的泛型是dishDto records集合 (集合里的每一个对象都是dish表的一条数据)在拿到records集合后 遍历 records集合—>stream流->map(取出集合数据) 将item对象(item就是records的一条记录)赋值给新new的dishDto对象,利用item的到分类id 根据id查询分类对象进而取出name属性值,将name设置给给dishDto的categoryName属性 最后再将流转换为DishDto泛型的list集合,再将带有categoryName属性的list集合设置 给dishDtoPage对象的records属性 */ //对象(都是Page对象)拷贝 但是不拷贝"records" 属性 因为这个records对应的泛型是dish // 而我们需要的泛型是dishDto 4-14 BeanUtils.copyProperties(pageInfo,dishDtoPage,"records"); //得到records集合 List records = pageInfo.getRecords(); //使用 流 遍历集合 List list = records.stream().map((item) -> { DishDto dishDto = new DishDto(); //因为上面new的DishDto的属性都是空值,需要将item对象赋值给dishDto BeanUtils.copyProperties(item,dishDto); Long categoryId = item.getCategoryId();//分类id //根据id查询分类对象 Category category = categoryService.getById(categoryId); if(category != null){ //得到分类名称 String categoryName = category.getName(); //给dishDto的categoryName属性设置值 dishDto.setCategoryName(categoryName); } return dishDto; }).collect(Collectors.toList());//将dishDto对象收集起来编程list集合 //经过上述操作,就得到了泛型为DishDto的list集合,而DishDto里还有categoryName属性 //再将带有categoryName属性的list集合设置给dishDtoPage对象的records属性 dishDtoPage.setRecords(list); return R.success(dishDtoPage); }

菜品管理业务开发_服务端_35

6. 修改菜品  4-166.1 需求分析  4-16

菜品管理业务开发_spring_36

6.2 代码开发 4-16  4-17

代码开发-梳理交互过程

在开发代码之前,需要梳理一下修改菜品时前端页面(add.html) 和服务端的交互过程:

1、页面发送ajax请求,请求服务端获取分类数据,用于菜品分类下拉框中数据展示

2、页面发送ajax请求,请求服务端,根据id查询当前菜品信息,用于菜品信息回显

3、页面发送请求,请求服务端进行图片下载,用于页图片回显

4、点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以json形式提交到服务端

开发修改菜品功能,其实就是在服务端编写代码去处理前端页面发送的这4次请求即可。

菜品管理业务开发_服务端_37

菜品管理业务开发_文件上传_38

根据菜品id查询数据

2、页面发送ajax请求,请求服务端,根据id查询当前菜品信息,用于菜品信息回显

菜品管理业务层接口DishService//根据菜品id来查询菜品信息和口味信息 4-17 public DishDto getByIdWithFlavor(Long id);业务层接口实现类DishServiceImpl/** * 根据菜品id查询菜品信息和对应的口味信息 4-17 * @param id * @return */ public DishDto getByIdWithFlavor(Long id) { //查询菜品基本信息,从dish表查询 Dish dish = this.getById(id); //对象拷贝,这里拷贝的是普通属性,不包括flavor DishDto dishDto = new DishDto(); BeanUtils.copyProperties(dish,dishDto); //DishFlavor byId = dishFlavorService.getById(id); //这里解释为什么不能直接用这行代码查口味表数据,因为这个id是菜品id不是口味表id,这样查查不到的 //所有要用下面的方法构造查询条件,查询条件就是口味对应的菜品id //查询当前菜品对应的口味信息,从dish_flavor表查询 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(DishFlavor::getDishId,dish.getId());//getDishId菜品id List flavors = dishFlavorService.list(queryWrapper); //这里将flavor设置进去 dishDto.setFlavors(flavors); return dishDto; } 菜品管理 DishController//修改菜品 之回显数据 4-17 //根据菜品id来查询菜品信息和口味信息 @GetMapping("/{id}") public R get(@PathVariable Long id){ //这里使用我们自己的方法,因为DishDto中包含了dish_flavor表 DishDto dishDto = dishService.getByIdWithFlavor(id); return R.success(dishDto); }

测试回显成功

菜品管理业务开发_服务端_39

4、点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以json形式提交到服务端

菜品管理业务开发_服务端_40

菜品管理业务开发_spring_41

更新菜品 保存修改  4-19菜品管理业务层接口DishService//更新菜品信息 同时更新口味信息 4-19 public void updateWithFlavor(DishDto dishDto);业务层接口实现类DishServiceImpl//修改菜品 4-19 @PutMapping public R update(@RequestBody DishDto dishDto){ log.info(dishDto.toString()); dishService.updateWithFlavor(dishDto); return R.success("新增菜品成功"); } 菜品管理 DishController//更新菜品信息 同时更新口味信息 4-19 @Override @Transactional public void updateWithFlavor(DishDto dishDto) { //更新dish表基本信息 this.updateById(dishDto); //这里解释为什么不能直接修改口味表,因为一个菜品可能对应多个口味而且,修改后的也可能是修改多个口味 // ,直接修改不知道修改哪一条,更不知道修改的哪条对应数据库的哪条记录,所以直接删除在添加 //清理当前菜品对应口味数据---dish_flavor表的delete操作 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.eq(DishFlavor::getDishId,dishDto.getId()); dishFlavorService.remove(queryWrapper); //添加当前提交过来的口味数据---dish_flavor表的insert操作 List flavors = dishDto.getFlavors(); //这里和添加一样的问题 继续为口味表添加菜品id flavors = flavors.stream().map((item) -> { item.setDishId(dishDto.getId()); return item; }).collect(Collectors.toList()); dishFlavorService.saveBatch(flavors); }

测试成功

菜品管理业务开发_服务端_42

菜品管理业务开发_服务端_43

菜品管理业务开发_文件上传_44

7. 菜品售卖状态  自己实现  

停售  起售(起售传来的请求几乎和停售一样,只是 0-->1  也就是状态值的差异而已)

菜品管理业务开发_spring_45

菜品管理业务开发_文件上传_46

批量停售  批量起售 (批量起售传来的请求几乎和批量停售一样,只是 0-->1  也就是状态值的差异而已)

菜品管理业务开发_spring_47

菜品管理业务开发_spring_48

由上图分析可知,四种功能的请求路径一样,且都使用了restful风格,因此可以封装成一个代码实现

DishController//修改菜品售卖状态 ,自己实现的 可以批量可以单个 @PostMapping("/status/{status}") public R stop(@PathVariable int status,@RequestParam List ids){ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.in(Dish::getId,ids);//先构造id(可能一个也可能多个,因为我们单独停售起售和批量写一起了) //在构造售卖状态 Dish dish = new Dish(); dish.setStatus(status); dishService.update(dish,queryWrapper); return R.success("菜品售卖状态修改成功"); }

测试成功

菜品管理业务开发_服务端_49

8. 删除和批量删除   自己实现

删除一个

菜品管理业务开发_服务端_50

菜品管理业务开发_spring_51

批量删除

菜品管理业务开发_文件上传_52

菜品管理业务开发_服务端_53

由上图可知,删除和批量删除请求路径是一样的,所以可以封装成一个方法

我们设置处在售卖状态的菜品不能删除

菜品管理业务层接口DishService//删除菜品同时删除和菜品关联的口味表数据 自己实现 public void removeWithDish(List ids); 菜品管理业务层接口实现类DishServiceImpl//删除菜品同时删除和菜品关联的口味表数据 自己实现 @Override public void removeWithDish(List ids) { //查询菜品状态看看是否处于售卖状态,看看是否可以删除 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); queryWrapper.in(Dish::getId,ids); queryWrapper.eq(Dish::getStatus,1); //这里的思想是根据id和status查询,如果查询出来的数据大于0,就证明处于售卖状态,否则为停售状态 int count = this.count(queryWrapper); if(count > 0){ //如果不能删除,抛出一个业务异常 throw new CustomException("菜品正在售卖中,不能删除"); } //如果可以删除,先删除菜品表中的数据---dish this.removeByIds(ids); //接着删除口味表章关联的数据 LambdaQueryWrapper dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper(); dishFlavorLambdaQueryWrapper.in(DishFlavor::getDishId,ids); dishFlavorService.remove(dishFlavorLambdaQueryWrapper); } DishController//删除菜品,自己实现 可以批量可以单个 @DeleteMapping public R delete(@RequestParam List ids){ //调用我们自己的方法,因为删除操作涉及了两张表菜品表和口味表 dishService.removeWithDish(ids); return R.success("删除菜品成功"); }

测试成功

菜品管理业务开发_服务端_54

有菜品在售卖不能删除

菜品管理业务开发_spring_55



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3