文件上传下载
预准备
前端代码:
会动态生成一个图像元素。
代码实现
文件上传
在 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);
}
}
文件下载
先上传再发送请求下载下来,通过标签展示数据。因为后端回传了数据名称 filename,所以 response.data 的值就是这个。这里发送请求 download
/**
* 文件下载
* @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();
}
}
新增菜品
预准备
dish 表:
dish_flavour 表:
前端代码
代码实现
创建相应的 dishflavor 基本结构。
查询分类数据
1 代表菜品分类,2 代表套餐分类。
/**
* 查询菜品数据,用于前端下拉菜单中展示
* @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);
}
新增菜品
在 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("新增菜品成功");
}
菜品信息分页查询
预准备
因为 dto 这个类只包含了菜品 id 没有包含名称,所以还要做一些额外的处理。用 Dto 来扩展出这个菜品名称。
展示菜品图片的前端代码:
代码实现
在 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);
}
修改菜品
预准备
代码实现
数据回显
在 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);
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于