首页 > 其他分享 >菜品管理业务开发

菜品管理业务开发

时间:2023-06-18 14:03:28浏览次数:27  
标签:dishDto 业务 开发 菜品 dish import com id

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

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

1.1 文件上传介绍  4-2

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

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

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

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

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

举例:

<form method="post" action=" /common/upload" enctype="multipart/form-data">
    <input name="myFile" type="file" />
    <input type-="submit" value="提交" />
</form>

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

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

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

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

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

菜品管理业务开发_spring_05

完成功能

文件上传和下载的控制器类CommonController  4-3

package 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<String> 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类拿到图片资源

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

菜品管理业务开发_spring_07

菜品管理业务开发_文件上传_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-4

package 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<String> 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添加图片 临时文件转存成功

菜品管理业务开发_文件上传_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-6

4.1 需求分析  4-6

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

菜品管理业务开发_spring_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<DishFlavor> {
}

菜品口味 业务层接口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<DishFlavor> {
}

菜品口味 业务层接口实现类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<DishFlavorMapper,DishFlavor> 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请求,请求服务端获取菜品分类数据并展示到下拉框中

菜品管理业务开发_spring_17

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

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

        List<Category> list = categoryService.list(queryWrapper);
        return R.success(list);
    }

菜品管理业务开发_spring_19

第二三步

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

 我们已经在上面实现了

第四步  4-10

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

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

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

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

菜品管理业务开发_spring_22

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

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

数据传输对象 DishDto
package 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<DishFlavor> 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<DishMapper,Dish> 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<DishFlavor> 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);
    }
}

是事务起作用

菜品管理业务开发_spring_25

菜品管理 DishController
package 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<String> 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-12

5.1 需求分析  4-12

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

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

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

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

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

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

//菜品分页查询  4-13
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){
        log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);

        //构造分页构造器
        //泛型只简单的使用Dish是不行的,因为没办法把菜品分类名称展示出来,所以还需要数据传输对象DTO 4-14
        Page<Dish> pageInfo = new Page<>(page, pageSize);
        //构造条件构造器
        LambdaQueryWrapper<Dish> 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

图解

菜品管理业务开发_spring_33

代码实现  4-14

首先声明注入CategoryService属性

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

DishController

 //菜品分页查询  4-13
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){
        log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);

        //构造分页构造器
        //泛型只简单的使用Dish是不行的,因为没办法把菜品分类名称展示出来,所以还需要数据传输对象DTO 4-14
        Page<Dish> pageInfo = new Page<>(page, pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        //构造条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        //添加过滤条件
        queryWrapper.like(name!=null,Dish::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);

        //执行分页查询
        //这条语句会将我们查询到的数据进行封装 全部封装进Page的对象pageInfo
        dishService.page(pageInfo,queryWrapper);

        /*
        解释
           由结果可以看出,我们的菜品分类名称并没有展示出来,这是为什么呢?因为前端需要的是菜品分
           类name属性,而我们后端给他传过去的是菜品分类的id,原因就在于我们用的是dish作为泛型来
           接收(Page<Dish> pageInfo = new Page<>(page, pageSize);),而dish里面没
           有name属性,但是dishdto里面由categoryName属性,所以我们在
           写一个Page<DishDto> 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<Dish> records = pageInfo.getRecords();

        //使用 流 遍历集合
        List<DishDto> 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);
    }

菜品管理业务开发_spring_35

6. 修改菜品  4-16

6.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<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());//getDishId菜品id
        List<DishFlavor> flavors = dishFlavorService.list(queryWrapper);
        
        //这里将flavor设置进去
        dishDto.setFlavors(flavors);

        

        return dishDto;
    }
菜品管理 DishController
//修改菜品 之回显数据 4-17
    //根据菜品id来查询菜品信息和口味信息
    @GetMapping("/{id}")
    public R<DishDto> get(@PathVariable Long id){

        //这里使用我们自己的方法,因为DishDto中包含了dish_flavor表
        DishDto dishDto = dishService.getByIdWithFlavor(id);

        return R.success(dishDto);

    }

测试回显成功

菜品管理业务开发_spring_39

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

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

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

更新菜品 保存修改  4-19

菜品管理业务层接口DishService
//更新菜品信息 同时更新口味信息  4-19
    public void updateWithFlavor(DishDto dishDto);
业务层接口实现类DishServiceImpl
//修改菜品  4-19
    @PutMapping
    public R<String> 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<DishFlavor> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());
        dishFlavorService.remove(queryWrapper);

        //添加当前提交过来的口味数据---dish_flavor表的insert操作
        List<DishFlavor> flavors = dishDto.getFlavors();

        //这里和添加一样的问题  继续为口味表添加菜品id
        flavors = flavors.stream().map((item) -> {
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());

        dishFlavorService.saveBatch(flavors);
    }

测试成功

菜品管理业务开发_spring_42

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

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

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

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

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

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

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

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

菜品管理业务开发_spring_48

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

DishController

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

        //在构造售卖状态
        Dish dish = new Dish();
        dish.setStatus(status);

        dishService.update(dish,queryWrapper);

        return R.success("菜品售卖状态修改成功");
    }

测试成功

菜品管理业务开发_spring_49

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

删除一个

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

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

批量删除

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

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

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

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

菜品管理业务层接口DishService

//删除菜品同时删除和菜品关联的口味表数据  自己实现
    public void removeWithDish(List<Long> ids);

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

//删除菜品同时删除和菜品关联的口味表数据  自己实现
    @Override
    public void removeWithDish(List<Long> ids) {
        //查询菜品状态看看是否处于售卖状态,看看是否可以删除
        LambdaQueryWrapper<Dish> 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<DishFlavor> dishFlavorLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dishFlavorLambdaQueryWrapper.in(DishFlavor::getDishId,ids);

        dishFlavorService.remove(dishFlavorLambdaQueryWrapper);


    }

DishController

//删除菜品,自己实现  可以批量可以单个
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids){

        //调用我们自己的方法,因为删除操作涉及了两张表菜品表和口味表
        dishService.removeWithDish(ids);

        return R.success("删除菜品成功");
    }

测试成功

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

有菜品在售卖不能删除

菜品管理业务开发_spring_55

标签:dishDto,业务,开发,菜品,dish,import,com,id
From: https://blog.51cto.com/u_15784725/6508345

相关文章

  • day00 python开发目录
    课程安排day01环境搭建和基础入门day02python基础day03数据类型day04数据类型和函数day05函数day06函数进阶day07模块day08模块和面向对象day09模块和面向对象day10模块和面向对象day11前端开发day12前端开发day13前端开发day14MySQL数据库day15......
  • Android-NDK开发——基本概念
    在Android开发中,有时候出于安全,性能,代码共用的考虑,需要使用C/C++编写的库。虽然在现代化工具链的支持下,这个工作的难度已经大大降低,但是毕竟万事开头难,初学者往往还是会遇到很多不可预测的问题。本篇就是基于此背景下写的一份简陋指南,希望能对刚开始编写C/C++库的读者有所帮助。......
  • 如何查看网站的开发信息
    WebTechnologiesusedbyCnblogs.com(w3techs.com)这个网站可以查看网站的开发信息。w3techs.com 例如上面就显示了博客园的后端是ASP。。。。。。。妈耶,一直以为是PHP前端居然用了VUE。666 ......
  • Flutter 库:提升开发体验——Quick
    Flutter库:提升开发体验——Quick文章目录Flutter库:提升开发体验——Quick一、概述1、简介2、功能3、官方资料4、思考二、基本使用1、安装2、基本使用3、运行结果三、List列表扩展示例四、Map映射扩展示例五、其它示例一、概述1、简介Quick是一个功能强大的Flutter包,旨在通......
  • v072冒险岛sf开发周记(一)
      上周末的时候看到tx代理了冒险岛手游,但是又还没上线,便回忆起自己从前玩冒险岛的时光。那时候和邻居哥哥们,和同学一起玩,只有冒险家职业,消磨了很多的时光,也认识了一些友善的网络好友,虽然打怪升级真的很慢,也没有好装备很菜,但是和朋友们一起玩的时候还是很快乐的,一起刷刷刷。也......
  • PHP开发:代码风格、重构和设计模式的实践
    一、代码风格和规范:采用一致的代码风格和规范有助于提高代码的可读性和可维护性。我们将介绍一些常见的PHP代码风格指南,如PSR-12(PHPStandardRecommendation),以及一些静态代码分析工具,如PHPCodeSniffer,可以帮助您自动检测代码规范问题。示例代码风格(使用PSR-12):<?phpnamespaceV......
  • PHP开发:版本管理、服务器配置和最佳实践
    一、PHP版本和扩展管理:在PHP开发中,使用最新版本的PHP和相关扩展非常重要。版本更新通常包含新功能、修复漏洞和提高性能。我们将介绍如何使用包管理器(如Composer)来管理PHP的版本和扩展,并演示如何安装和更新它们。示例代码:#使用Composer安装PHP依赖包composerrequirevendor/pac......
  • 如何通过专业化物业管理系统开发,提升物业管理效率?
    物业管理需要高效的工具来支持,这就需要专业化的物业管理系统开发。随着现代科技的发展,专业化物业管理系统作为一种新型的信息管理系统,被广泛应用于物业管理领域。而专业化物业管理系统开发可以帮助物业管理公司提升管理效率,提高服务质量,同时也能够有效降低物业管理成本。接下来广州......
  • Python3网络爬虫开发实战阅读笔记
    基本库的使用网络请求库urllib(HTTP/1.1)Python自带请求库,繁琐基础使用:略requests(HTTP/1.1)Python常用第三方请求库,便捷基础使用:略httpx(HTTP/2.0)Python第三方库,支持HTTP/2.0,支持异步请求,支持Python的async请求模式pipinstall'httpx[http2]'基础使用:与requests相似,默认......
  • HarmonyOS应用开发者基础认证题库
    祝大家都顺利通过判断题1.Web组件对于所有的网页都可以使用zoom(factor:number)方法进行缩放。错误(False)2.每一个自定义组件都有自己的生命周期正确(True)3.每调用一次router.pushUrl()方法,默认情况下,页面栈数量会加1,页面栈支持的最大页面数量为32。正确(True)4.所......