一、文件的上传下载
1.1 文件上传基础
文件上传,也称为upload,是指将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程。文件上传在项目中应用非常广泛,我们经常发微博、发微信朋友圈都用到了文件上传功能。
文件上传时,对页面的form表单有如下要求:
method=“post” | 采用post方式提交数据 |
---|---|
enctype=“multipart/form-data” | 采用multipart格式上传文件 |
type=“file” | 使用input的file控件上传 |
服务端要接收客户端页面上传的文件,通常都会使用Apache的两个组件:
commons-fileupload
commons-io
Spring框架在spring-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要
一个MultipartFile类型的参数即可接收上传的文件,例如:
2.2 文件下载基础
文件下载,也称为download,是指将文件从服务器传输到本地计算机的过程。
通过浏览器进行文件下载,通常有两种表现形式:
以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录
直接在浏览器中打开
通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程。
二、文件上传—upload
2.1 代码实现
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
log.info(file.toString());
//原始文件名
String originFilename = file.getOriginalFilename();
String suffix = originFilename.substring(originFilename.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();
}
return R.success(fileName);
}
2.2 函数学习
String suffix =
originFilename.substring(originFilename.lastIndexOf(“.”));
substring函数
函数源码解释
Returns a string that is a substring of this string. The substring begins with the character at the specified index and extends to the end of this string.
substring() 方法返回字符串的子字符串。
语法
public String substring(int beginIndex)
或
public String substring(int beginIndex, int endIndex)
参数
beginIndex – 起始索引(包括), 索引从 0 开始。
endIndex – 结束索引(不包括)。
实例
public class RunoobTest {
public static void main(String args[]) {
String Str = new String("This is text");
System.out.print("返回值 :" );
System.out.println(Str.substring(4) );
System.out.print("返回值 :" );
System.out.println(Str.substring(4, 10) );
}
}
以上程序执行结果为:
返回值 : is text
返回值 : is te
lastIndexOf函数
直接上代码
String s = "01234560123456";
int a = s.lastIndexOf('1'); // 返回最后一个字符1的下标
int b = s.lastIndexOf("23"); // 返回最后一个字符串“23”的下标
int c = s.lastIndexOf('1',5); // 以下标5为终点,返回最后一个字符1的下标
int d = s.lastIndexOf("23",5); // 以下标5为终点,返回最后一个字符串“23”的下标
System.out.println(a + " " + b + " " + c + " "+ d);
注意 lastIndexOf(“str”, index)方法,这里返回的是 从下标0开始,以index结尾(包含index下标)之间搜索最后一个字符或字符串下标。
indexOf()方法:
String s = "01234560123456";
int a = s.indexOf('1'); // 返回第一个字符1的下标
int b = s.indexOf("23"); // 返回第一个字符串“23”的下标
int c = s.indexOf('1',5); // 以下标5开始,返回第一个字符1的下标
int d = s.indexOf("23",5); // 以下标5开始,返回第一个字符串“23”的下标
System.out.println(a + " " + b + " " + c + " "+ d);
三、 文件下载—download
3.1 代码实现
/**
* 文件下载
* @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();
}
//关闭资源
fileInputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
四、 新增菜品
4.1 代码开发-梳理交互过程
1、页面(backend/page/food/add.html)发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中
2、页面发送请求进行图片上传,请求服务端将图片保存到服务器
3、页面发送请求进行图片下载,将上传的图片进行回显
4、点击保存按钮,发送ajax请求,将菜品相关数据以json形式提交到服务端
开发新增菜品功能,其实就是在服务端编写代码去处理前端页面发送的这4次请求即可
4.2 获取分类数据
/**
* 菜品管理中获取分类数据
* @param type
* @return
*/
@GetMapping("/list")
public R<List<Category>> getCategoryList(@RequestParam Integer type){
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Category::getType,type);
queryWrapper.orderByDesc(Category::getSort).orderByDesc(Category::getUpdateTime);
List<Category> list= categoryService.list(queryWrapper);
return R.success(list);
}
4.3 代码实现
代码开发-导入DT0
导入DishDto,用于封装页面提交的数据
@Data
Pablic class DishDto extends Dish
private List<DishFlavor>flavors new ArrayList<>();
private String categoryName;
private Integer copies;
注意事项
DTO,全称为Data Transfer Object,即数据传输对象,一般用于展示层与服务层之间的数据传输。
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;
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
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 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;
@Service
public class DishServiceImpl extends ServiceImpl<DishMapper, Dish> implements DishService {
@Autowired
private DishFlavorService dishFlavorService;
/**
* 新增菜品,同时保存对应的口味数据
* @param dishDto
*/
@Transactional
public void saveWithDishFlavor(DishDto dishDto) {
//保存菜品的基本信息到菜品表dish
this.save(dishDto);
Long dishId = dishDto.getId();
//保存菜品的口味到dishFlavor
//将dishId保存在dishFlavor表中
List<DishFlavor> flavorList = dishDto.getFlavors();
flavorList = flavorList.stream().map((item) ->{
item.setDishId(dishId);
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavorList);
}
}
DishController
/**
* 新增菜品
* @param dishDto
* @return
*/
@PostMapping
public R<String> addDish(@RequestBody DishDto dishDto){
log.info(dishDto.toString());
dishService.saveWithDishFlavor(dishDto);
return R.success("保存成功");
}
五、 菜品信息分页查询
5.1 代码开发
这里需要注意的是DishDto继承了Dish,所有这样才能进行全部显示
DishController
/**
* 菜品的分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> findPage(@RequestParam Integer page,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String name){
Page<Dish> ipage = new Page<>(page,pageSize);
Page<DishDto> dishDtoPage = new Page<>();
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
if(!"".equals(name)){
queryWrapper.like(Dish::getName,name);
}
queryWrapper.orderByDesc(Dish::getUpdateTime);
dishService.page(ipage,queryWrapper);
// 对象拷贝
BeanUtils.copyProperties(ipage,dishDtoPage,"records");
List<Dish> records = ipage.getRecords();
List<DishDto> list = records.stream().map((item) ->{
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item,dishDto);
Long categoryId = item.getCategoryId();//分类id
//根据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);
}
下面这一步是最重要的,将category_id查询变成分类名称
// 对象拷贝
BeanUtils.copyProperties(ipage,dishDtoPage,"records");
List<Dish> records = ipage.getRecords();
List<DishDto> list = records.stream().map((item) ->{
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item,dishDto);
Long categoryId = item.getCategoryId();//分类id
//根据id查询分类对象
Category category = categoryService.getById(categoryId);
if(category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
return dishDto;
}).collect(Collectors.toList());
dishDtoPage.setRecords(list);
六、菜品回显加保存
6.1 交互过程
在开发代码之前,需要梳理一下修改菜品时前端页面(add.html)和服务端的交互过程:
1、页面发送jax请求,请求服务端获取分类数据,用于菜品分类下拉框中数据展示
2、页面发送ajax请求,请求服务端,根据id查询当前菜品信息,用于菜品信息回显
3、页面发送请求,请求服务端进行图片下载,用于页图片回显
4、点击保存按钮,页面发送ajx请求,将修改后的菜品相关数据以)son形式提交到服务端
6.2 代码实现
页面回显
DishServiceImpl实现类中写好方法
/**
* 根据菜品id进行查询信息,进行回显
* @param id
* @return
*/
@Override
public DishDto getWithDish(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> dishFlavors = dishFlavorService.list(queryWrapper);
dishDto.setFlavors(dishFlavors);
return dishDto;
}
更新菜品信息
/**
* 更新菜品信息
* @param dishDto
*/
@Override
@Transactional
public void updateWithDishFlavor(DishDto dishDto) {
this.updateById(dishDto);
// 删除口味,在dishflavor表中
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());
dishFlavorService.remove(queryWrapper);
//添加当前提交过来的口味数据,重新保存在dish_flavor表中
List<DishFlavor> flavorList = dishDto.getFlavors();
flavorList = flavorList.stream().map((item) ->{
item.setDishId(dishDto.getId());
return item;
}).collect(Collectors.toList());
dishFlavorService.saveBatch(flavorList);
}
七、 菜品删除和批量删除
由于此部分内容为自己自由编写,代码实现不一定同意,仅供参考
7.1 代码实现
1.删除需要操作两个表,一个是dish表,一个是dish_flavor
2.主要做两件事删除菜品和删除菜品口味
/**
* 删除于批量删除
* @param id
* @return
*/
@DeleteMapping
public R<String> deleteDish(@RequestParam("ids") Long[] id){
log.info(id.toString());
//删除口味
for (int i = 0; i < id.length; i++) {
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,id[i]);
dishFlavorService.remove(queryWrapper);
}
List<Long> idList = Arrays.asList(id);
dishService.removeByIds(idList);
return R.success("删除成功");
}
八、停售与批量停售
8.1 代码实习
/**
* 停售起售和批量停售起售
* @param status
* @param ids
* @return
*/
@PostMapping("/status/{status}")
public R<String> updateStatus(@PathVariable Integer status,Long[] ids){
for (int i = 0; i < ids.length; i++) {
Long id = ids[i];
Dish dish = dishService.getById(id);
dish.setStatus(status);
dishService.updateById(dish);
}
return R.success("菜品状态更新成功");
}
九、 套餐管理说明
由于菜品管理和套餐管理逻辑上基本相同,所以就不更新套餐管理,其实只需要去复制代码更改就行,就写一个菜品回显的代码,其他照抄
/**
* 套餐管理中查找菜品回显
* @param dish
* @return
*/
@GetMapping("/list")
public R<List<Dish>> queryDishById(Dish dish){
LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId()!=null,Dish::getCategoryId,dish.getCategoryId());
queryWrapper.orderByDesc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
queryWrapper.eq(Dish::getStatus,1);
List<Dish> list= dishService.list(queryWrapper);
return R.success(list);
}
}