瑞吉外卖 04 CRUD 菜品 + 文件上传下载

文件上传下载

预准备

image

image

image

image

image

前端代码:

image

会动态生成一个图像元素。

代码实现

文件上传

在resource/backend/page下创建demo文件,将资料/文件上传下载页面中upload.html复制到这里。在controller下创建CommonController类,

此处形参file必须与form data对应的name一致。

在controller下编写:

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;

/**
 * @author 文件上传和下载
 * @create 2023-06-27 15:42
 */
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
    
    

    @Value("${reggie.path}")
    private String basePath;

    @PostMapping("/upload")
    public R<String> upload(MultipartFile file){
    
    
        //file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除
        log.info(file.toString());

        //originalFilename原始文件名,suffix截取的abc.jpg的后缀jpg
        String originalFilename = file.getOriginalFilename();
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用UUID重新生成文件名称,防止造成文件覆盖
        String fileName = UUID.randomUUID().toString()+suffix;

        //创建一个目录对象
        File dir=new File(basePath);
        //判断目录是否存在
        if(!dir.exists()){
    
     //不存在的话需要创建
            dir.mkdirs();
        }

        try{
    
    
            //将临时文件转存到指定位置
            file.transferTo(new File(basePath+fileName));
        }catch (IOException e){
    
    
            e.printStackTrace();
        }

        //因为后续需要文件名称保存到新增菜品的字段当中去,所以这里需要返回fileName
        return R.success(fileName);
    }
}

在springboot配置文件下指定缓存路径:

reggie:
  path: D:\img

注意:path冒号后面必须要有空格,否则会报Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException:错误。

在test包下创建一个UploadFileTest类,进行单元测试,看文件路径输出是否正确:

import org.junit.jupiter.api.Test;

/**
 * @author shkstart
 * @create 2023-06-27 16:17
 */
public class UploadFileTest {
    
    
    @Test
    public void test1(){
    
    
        String fileName="adsd.jpg";
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        System.out.println(suffix);
    }
}

文件下载

image

image

先上传再发送请求下载下来,通过标签展示数据。因为后端回传了数据名称filename,所以response.data的值就是这个。这里发送请求download

image

    /**
     * 文件下载
     * @param name
     * @param response
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response){
    
    
        try{
    
    
            //输入流,通过输入流读取文件内容
            FileInputStream fileInputStream=new FileInputStream(new File(basePath+name);

            //输出流,通过输出流文件写回浏览器,在浏览器展示图片
            ServletOutputStream outputStream=response.getOutputStream();

            //设置资源类型
            response.setContentType("image/jpeg");

            int len=0;
            byte[] bytes=new byte[1024];
            while ((len=fileInputStream.read(bytes))!=-1){
    
    
                outputStream.write(bytes,0,len);
                outputStream.flush();
            }

            //关闭资源
            outputStream.close();
            fileInputStream.close();
        }catch (Exception e){
    
    
            e.printStackTrace();
        }
    }

新增菜品

预准备

image

image

dish表:

image

dish_flavour表:

image

image

image

image

前端代码

image

代码实现

创建相应的dishflavor基本结构。

查询分类数据

image

1代表菜品分类,2代表套餐分类。

image

 /**
     * 查询菜品数据,用于前端下拉菜单中展示
     * @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);
    }

新增菜品

image

image

image

image

image

在reggie下创建一个dto包,从资料复制dishDto。

在dishservice下,新增一个public void addWithFlavor(DishDto dishDto);方法,在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;

/**
 * @author shkstart
 * @create 2023-06-26 21:21
 */
@Slf4j
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper,Dish> implements DishService{
    
    
    @Autowired
    private DishFlavorService dishFlavorService;

    /**
     * 新增菜品,同时保存对应的口味数据
     * @param dishDto
     */
    //因为涉及到多张表操作,所以要开启事务操作
    @Transactional
    public void addWithFlavor(DishDto dishDto){
    
    
        //保存菜品的基本信息到菜品表dish
        this.save(dishDto);

        //为每个口味加上菜品id信息
        Long dishDtoId=dishDto.getId();//菜品id

        //lambda表达式+mybatisplus语法
        List<DishFlavor> flavors=dishDto.getFlavors();
        flavors=flavors.stream().map((item)->{
    
    
            item.setDishId(dishDtoId);
            return item;
        }).collect(Collectors.toList());

        //保存菜品口味数据到菜品口味表dish_flavor
        dishFlavorService.saveBatch(flavors);
    }
}

然后在启动类前加个@EnableTransactionManagement注解。

最后在DishController里面写:

    /**
     * 新增菜品,requestbody是反序列化前端传来的json数据
     * @param dishDto
     * @return
     */
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto){
    
    
        log.info(dishDto.toString());
        dishService.addWithFlavor(dishDto);
        return R.success("新增菜品成功");
    }

菜品信息分页查询

预准备

image

image

image

因为dto这个类只包含了菜品id没有包含名称,所以还要做一些额外的处理。用Dto来扩展出这个菜品名称。

image

展示菜品图片的前端代码:

image

image

代码实现

在dishController下写:

/**
     * 菜品信息分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){
    
    
        //构造分页构造对象
        Page<Dish> pageInfo=new Page<>(page,pageSize);
        Page<DishDto> dishDtoPage=new Page<>(page,pageSize);

        //条件构造器
        LambdaQueryWrapper<Dish> queryWrapper=new LambdaQueryWrapper<>();
        //添加过滤条件
        queryWrapper.like(name!=null,Dish::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);
        //执行分页查询
        dishService.page(pageInfo,queryWrapper);

        //对象拷贝,拷贝的分页信息,因为dishDto没有条件构造器,所以要先拷贝他的分页信息
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");

        List<Dish> records = pageInfo.getRecords();
        List<DishDto> list = records.stream().map((item)->{
    
    
            DishDto dishDto=new DishDto();
            //拷贝的数据信息,并且加了一个字段存储查询id对应的菜品名称
            BeanUtils.copyProperties(item,dishDto);

            //根据id查询分类
            Long categoryId=item.getCategoryId();
            Category category = categoryService.getById(categoryId);

            //因为导入的数据有些菜品没有分类名称,所以加个判断以防报错
            if(category!=null){
    
    
                String categoryName =category.getName();
                dishDto.setCategoryName(categoryName);
            }

            return dishDto;
        }).collect(Collectors.toList());
        dishDtoPage.setRecords(list);


//        return R.success(pageInfo);
        return R.success(dishDtoPage);
    }

修改菜品

预准备

image

image

代码实现

数据回显

DishService下加一个public DishDto getByIdWithFlavor(Long id);方法,根据id查询菜品信息和对应的口味信息。

DishServiceImpl实现类下,写:

     /**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    @Override
    public DishDto getByIdWithFlavor(Long id) {
    
    
        //查询菜品基本信息,从dish表查询
        Dish dish=this.getById(id);

        DishDto dishDto=new DishDto();
        BeanUtils.copyProperties(dish,dishDto);

        //查询当前菜品对应的口味信息,从dishFlavor表查询
        LambdaQueryWrapper<DishFlavor> queryWrapper=new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());
        List<DishFlavor> flavors = dishFlavorService.list(queryWrapper);
        dishDto.setFlavors(flavors);
        return dishDto;
    }

DishController下,编写:

    /**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R<DishDto> get(@PathVariable Long id){
    
    
        DishDto dishDto=dishService.getByIdWithFlavor(id);
        return R.success(dishDto);
    }

修改菜品

跟新增类似。

DishController类下,新增:

    /**
     * 修改菜品,requestbody是反序列化前端传来的json数据
     * @param dishDto
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
    
    
        log.info(dishDto.toString());
        dishService.updateWithFlavor(dishDto);
        return R.success("新增菜品成功");
    }

在服务类下,新增public void updateWithFlavor(DishDto dishDto);方法,并在实现类下重写该方法:

@Transactional
    @Override
    public void updateWithFlavor(DishDto dishDto) {
    
    
        //更新dish的基本信息
        this.updateById(dishDto);

        //清理当前菜品对应口味数据,dishflavor表的delete操作
        LambdaQueryWrapper<DishFlavor> queryWrapper=new LambdaQueryWrapper();
        queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());//根据dishDto的菜品id查找dishFlavor中对应的DishId,这两是一个数值

        dishFlavorService.remove(queryWrapper);

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

        //捆绑口味和菜品id
        flavors=flavors.stream().map((item)->{
    
    
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());

        //保存菜品口味数据到菜品口味表dish_flavor
        dishFlavorService.saveBatch(flavors);
    }

猜你喜欢

转载自blog.csdn.net/weixin_46066669/article/details/131427217