04 CRUD 菜品 + 文件上传下载

本贴最后更新于 694 天前,其中的信息可能已经时异事殊

文件上传下载

预准备

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); }
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3201 引用 • 8216 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...