01、文件上传下载
1、文件上传介绍
文件上传,也称为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>
2、文件下载介绍
文件下载,也称为download
,是指将文件从服务器传输到本地计算机的过程
通过浏览器进行文件下载,通常有两种表现形式:
- 以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录
- 直接在浏览器中打开
通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程
3、文件上传代码实现
- 请求地址:
http://localhost:8080/common/upload
- 请求类型:
POST
- 请求参数:
file
在全局配置application.yml
中配置文件存储路径
reggie:
path: F:\瑞吉外卖\temp\
目录:controller
package cn.mu00.reggie.controller;
import cn.mu00.reggie.common.R;
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;
/**
* 文件上传和下载
*/
@RestController
@RequestMapping("/common")
public class CommonController {
@Value("${reggie.path}")
private String basePath;
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
// file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件会删除
// 原始文件名
String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.indexOf("."));
// 使用UUID重新生成文件名,防止文件名称重复造成文件覆盖
String fileName = UUID.randomUUID() + suffix;
// 创建一个目录对象
File dir = new File(basePath);
// 判断当前目录是否存在
if (!dir.exists()){
// 目录不存在,需要创建
dir.mkdir();
}
try {
// 将临时文件转存到指定位置
file.transferTo(new File(basePath + fileName));
} catch (IOException e) {
e.printStackTrace();
}
return R.success(fileName);
}
}
4、文件下载代码实现
- 请求地址:
http://localhost:8080/common/download?name=文件名
- 请求类型:
GET
位置:CommonController
/**
* 文件下载
* @param name
* @param response
*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response){
try {
// 输入流,通过输入流读取文件内容
FileInputStream fileInputStream = new FileInputStream(basePath + name);
// 输出流,通过输出流将文件写回浏览器,在浏览器展示图片
ServletOutputStream outputStream = response.getOutputStream();
response.setContentType("image/jpeg");
int len;
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();
}
}
02、新增菜品
1、需求分析
菜品分类
- 请求地址:
http://localhost:8080/category/list?type=1
- 请求类型:
GET
- 请求参数:
type
新增菜品
- 请求地址:
http://localhost:8080/dish
- 请求类型:
POST
2、代码实现
01.获取菜品分类方法
位置:CategoryController
/**
* 根据条件查询分类数据
* @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);
}
02.DishFlavor实体类
package cn.mu00.reggie.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
菜品口味
*/
@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;
}
03.DishFlavorMapper
package cn.mu00.reggie.mapper;
import cn.mu00.reggie.entity.DishFlavor;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface DishFlavorMapper extends BaseMapper<DishFlavor> {
}
04.DishFlavorService
package cn.mu00.reggie.service;
import cn.mu00.reggie.entity.DishFlavor;
import com.baomidou.mybatisplus.extension.service.IService;
public interface DishFlavorService extends IService<DishFlavor> {
}
05.DishFlavorServiceImpl
package cn.mu00.reggie.service.impl;
import cn.mu00.reggie.entity.DishFlavor;
import cn.mu00.reggie.mapper.DishFlavorMapper;
import cn.mu00.reggie.service.DishFlavorService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service
public class DishFlavorServiceImpl extends ServiceImpl<DishFlavorMapper, DishFlavor> implements DishFlavorService {
}
06.DishController
package cn.mu00.reggie.controller;
import cn.mu00.reggie.service.DishFlavorService;
import cn.mu00.reggie.service.DishService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 菜品管理
*/
@RestController
@RequestMapping("/dish")
public class DishController {
@Autowired
private DishService dishService;
@Autowired
private DishFlavorService dishFlavorService;
}
07.DishDto
目录:dto
package cn.mu00.reggie.dto;
import cn.mu00.reggie.entity.Dish;
import cn.mu00.reggie.entity.DishFlavor;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
08.添加菜品方法
1、DishService
// 新增菜品,同时插入菜品对应的口味数据
public void saveWithFlavor(DishDto dishDto);
2、ReggieApplication
启动类开启事务注解支持
@EnableTransactionManagement(proxyTargetClass=true)
3、DishServiceImpl
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时插入菜品对应的口味数据
* @param dishDto
*/
@Override
@Transactional
public void saveWithFlavor(DishDto dishDto) {
// 保存菜品的基本信息
this.save(dishDto);
Long dishId = dishDto.getId();
// 菜品口味
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
item.setDishId(dishId);
return item;
}).collect(Collectors.toList());
// 保存菜品口味数据
dishFlavorService.saveBatch(flavors);
}
4、DishController
/**
* 新增菜品
* @param dishDto
* @return
*/
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveWithFlavor(dishDto);
return R.success("添加菜品成功");
}
03、菜品信息分页查询
1、需求分析
- 请求地址:
http://localhost:8080/dish/page?page=页码&pageSize=每页数量&name=模糊查询
- 请求类型:
GET
- 请求参数:
page
、pageSize
、[name]
- 注:
page
默认:1,pageSize
默认:10,[name]
可选参数
2、代码实现
位置:DishController
/**
* 菜品信息分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page<DishDto>> page(int page, int pageSize, String name){
// 分页构造器
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);
// 执行分页查询
dishService.page(pageInfo, queryWrapper);
// 对象拷贝
BeanUtils.copyProperties(pageInfo, dishDtoPage, "records");
List<Dish> records = pageInfo.getRecords();
List<DishDto> list = records.stream().map((item) -> {
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item, dishDto);
// 分类id
Long categoryId = item.getCategoryId();
// 根据id查询分类对象
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(dishDtoPage);
}
04、修改菜品
1、需求分析
查询指定菜品的信息
- 请求地址:
http://localhost:8080/dish/菜品id
- 请求类型:
GET
- 请求参数:
id
修改菜品
- 请求地址:
http://localhost:8080/dish
- 请求类型:
PUT
- 请求参数
2、代码实现
01.查询指定菜品的信息
1.DishService
// 根据id查询菜品信息和对应的口味信息
public DishDto getByIdWithFlavor(Long id);
2.DishServiceImpl
/**
* // 根据id查询菜品信息和对应的口味信息
* @param id
* @return
*/
@Override
public DishDto getByIdWithFlavor(Long id) {
// 查询菜品基本信息
Dish dish = this.getById(id);
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(dish, dishDto);
// 查询当前菜品对应的口味信息
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId, dish.getId());
List<DishFlavor> flavors = dishFlavorService.list(queryWrapper);
dishDto.setFlavors(flavors);
return dishDto;
}
3.DishController
/**
* 根据id查询菜品信息和对应的口味信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<DishDto> get(@PathVariable Long id){
DishDto dishDto = dishService.getByIdWithFlavor(id);
return R.success(dishDto);
}
02.修改菜品方法
1.DishService
// 更新菜品信息,同时更新对应的口味信息
public void updateWithFlavor(DishDto dishDto);
2.DishServiceImpl
/**
* 更新菜品信息,同时更新对应的口味信息
* @param dishDto
*/
@Override
@Transactional
public void updateWithFlavor(DishDto dishDto) {
// 更新菜品基本信息
this.updateById(dishDto);
// 清理当前菜品对应的口味数据
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId, dishDto.getId());
dishFlavorService.remove(queryWrapper);
// 添加当前菜品对应的口味数据
List<DishFlavor> flavors = dishDto.getFlavors();
flavors = flavors.stream().map((item) -> {
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavors);
}
3.DishController
/**
* 更新菜品信息,同时更新对应的口味信息
* @param dishDto
* @return
*/
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.updateWithFlavor(dishDto);
return R.success("修改菜品成功");
}
05、批量/删除菜品信息
1、需求分析
- 请求地址:
http://localhost:8080/dish?ids=id数组
- 请求类型:
DELETE
- 请求参数:
ids
2、代码实现
/**
* 删除菜品信息和对应的口味信息
* @param ids
* @return
*/
@DeleteMapping
public R<String> delete(Long[] ids){
// 删除菜品信息
dishService.removeByIds(Arrays.asList(ids));
// 删除对应的口味信息
for (Long dishId : ids) {
// 条件构造器
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
// 添加条件
queryWrapper.eq(DishFlavor::getDishId, dishId);
// 执行删除
dishFlavorService.remove(queryWrapper);
}
return R.success("菜品信息删除成功");
}
06、起售/停售菜品
1、请求分析
- 请求地址:
http://localhost:8080/dish/status/状态?ids=id数组
- 请求类型:
POST
- 请求参数:
status
:0 - 停售,1 - 起售、ids
2、代码实现
/**
* 起售/停售菜品
* @param status
* @param ids
* @return
*/
@PostMapping("/status/{status}")
public R<String> status(@PathVariable Integer status, Long[] ids){
for (Long dishId : ids) {
Dish dish = new Dish();
dish.setId(dishId);
dish.setStatus(status);
dishService.updateById(dish);
}
return R.success("菜品信息更新成功");
}