目录
1. 文件上传下载
1.1 上传upload
简述:将本地文件上传至服务器的过程,以便后续用户浏览或者下载。
前端
- 必须采用post方式提交数据
- 必须采用multipart格式上传文件
- 使用input的file控件上传
eg:
后端
服务器接收客户端页面上传的文件通常要使用Apache的两个组件:
- commons-fileupload
- commons-io
Spring在spring-web包中对其进行了封装,极大简化了服务端代码,只需在Controller的方法中声明一个MultipartFile类型的参数即可接收上传的文件。
1. 在CommonController.java中定义方法实现
//转存路径参数声明
@Value("${greenTea.path}")
private String basePath;
/**
* 文件上传
* @param file
* @return
*/
@PostMapping("/upload")
public R<String> upload(MultipartFile file){
//获取原始文件名
String originalFilename = file.getOriginalFilename();
//截取文件名后缀
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
//使用UUID重新生成文件名,防止文件名称重复造成文件覆盖
String fileName = UUID.randomUUID() + suffix;
//判断目录是否存在,如果不存在则创建目录
File dir = new File(basePath);
if(!dir.exists()){
dir.mkdirs();
}
//file是一个临时文件,需要转存到指定位置,否则请求结束后会自动删除
try {
file.transferTo(new File(basePath+fileName));
} catch (IOException e) {
throw new RuntimeException(e);
}
return R.success(fileName);
}
2. 配置文件application.yml中设置文件转存路径参数值:
greenTea:
path: D:\img\
1.2 下载download
简述:将文件从服务器传输到本地计算机或浏览器的过程。
/**
* 文件下载
* @param name
* @param response
* @throws IOException
*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response) throws IOException {
//通过输入流读取文件内容到服务器
FileInputStream fileInputStream = new FileInputStream(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();
}
2. 新增菜品
简述:管理员可以添加新的菜品,具体如下图:
该页面需要发送两个请求:
2.1 查询菜品分类
具体请求信息:
代码如下:
/**
* 查询菜品或套餐分类
* @param category
* @return
*/
@GetMapping("/list")
// 请求路径:category/list?type=1 传过来的参数可以使用(String type)接收,也可以使用(Category category)将type封装为该对象的一个属性,建议使用后者,因为通用性更好
public R<List<Category>> list(Category category){
//构造查询条件
LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
//添加查询条件
queryWrapper.eq(Category::getType,category.getType());
//添加排序条件:先按照sort升序排列,如果sort相同再按照更新时间降序排列
queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);
List<Category> categories = categoryService.list(queryWrapper);
return R.success(categories);
}
结果展示:
2.2 保存菜品及其相关信息
1. 创建dishDto实体类,用于封装增加菜品页面提交的数据;
注:DTO,全称Data Transfer Object ,数据传输对象,一般用于展示层与服务层之间的数据传输。
@Data
public class DishDto extends Dish {
private List<DishFlavor> flavors = new ArrayList<>();
private String categoryName;
private Integer copies;
}
2. 保存菜品信息到数据库,并且保存相应的口味信息。
注:涉及多张表操作,需要进行事务控制,在启动类上添加开启事务的注解@EnableTransactionManagement,同时在实现业务逻辑的方法上添加@Transactional 注解。
@EnableTransactionManagement //开启事务注解的支持
public class GreenTeaApplication {
public static void main(String[] args) {
SpringApplication.run(GreenTeaApplication.class,args);
log.info("项目启动成功...");
}
}
方法一:for增强
/**
* 保存新增的菜品信息和相应的口味信息
* @param dishDto
* @return
*/
@Transactional //因为操作多张表,需要进行事务控制,保证操作的原子性
@PostMapping
public R<String> save(@RequestBody DishDto dishDto){
//保存菜品信息
dishService.save(dishDto);
//获取菜品id
Long dishId = dishDto.getId();
//取出菜品口味信息
List<DishFlavor> flavors = dishDto.getFlavors();
//为每条菜品口味信息赋上菜品id并保存进数据库
for (DishFlavor dishFlavor : flavors) {
dishFlavor.setDishId(dishId);
dishFlavorService.save(dishFlavor);
}
return R.success("新增菜品成功");
}
方法二:stream流
3. 菜品信息分页查询
使用mybatis-plus封装的分页工具,除了需要菜品表里的信息外,还需要查询分类表中的分类信息。
/**
* 菜品信息分页查询
* @param page
* @param pageSize
* @param name
* @return
*/
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
//检验前端是否正常发送请求且是否被控制器正常接收
//log.info("page:{},pageSize:{},name:{}",page,pageSize,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);
//对象拷贝,将dish的分页信息复制到dishDto,但不复制其中的records属性(records中保存了查询的菜品信息)
BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");
//获取dish分页对象records属性中保存的菜品信息
List<Dish> dishRecords = pageInfo.getRecords();
//创建一个list集合用来保存dishDto的信息
List<DishDto> dtoRecords = new ArrayList<>();
//遍历dishRecords,将dish的全部信息拷贝给dishDto对象
//根据菜品表的分类id查询分类名,然后赋给dishDto中的categoryName属性
//将拼凑好的每一个dishDto类型数据全部加入集合中
for (Dish dish : dishRecords) {
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(dish,dishDto);
String categoryName = categoryService.getById(dish.getCategoryId()).getName(); //获取分类名
dishDto.setCategoryName(categoryName); //将分类名赋值给dishDto
dtoRecords.add(dishDto); //将dishDto添加到集合中
}
//将dtoRecords存入dishDtoPage对象中
dishDtoPage.setRecords(dtoRecords);
//最后返回分页信息对象,包含了前端所需的信息
return R.success(dishDtoPage);
}
4. 修改菜品
修改菜品信息需要发送两个请求:
4.1 根据id查询菜品信息
回显要修改的那个菜品的相关信息包括菜品口味信息,此处复用了增加菜品的页面。
/**
* 根据id查询菜品信息
* @param id
* @return
*/
@GetMapping("/{id}")
public R<DishDto> getById(@PathVariable Long id){
Dish dish = dishService.getById(id); //查出菜品信息
//查询菜品口味信息
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,id);
List<DishFlavor> dishFlavors = dishFlavorService.list(queryWrapper);
//设置要展示的菜品信息包括口味信息
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(dish,dishDto); //将dish属性值复制给dishDto
dishDto.setFlavors(dishFlavors);
return R.success(dishDto);
}
4.2 修改菜品以及口味信息
/**
* 修改菜品
* @param dishDto
* @return
*/
@Transactional
@PutMapping
public R<String> update(@RequestBody DishDto dishDto){
//保存菜品信息
dishService.updateById(dishDto);
//获取菜品id
Long dishId = dishDto.getId();
//删除原来的口味数据
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,dishId);
dishFlavorService.remove(queryWrapper);
//取出新的菜品口味信息
List<DishFlavor> flavors = dishDto.getFlavors();
//为每条菜品口味信息赋上菜品id并保存进数据库
for (DishFlavor dishFlavor : flavors) {
dishFlavor.setDishId(dishId);
dishFlavorService.save(dishFlavor);
}
return R.success("修改成功");
}
5. 修改菜品售卖状态(可批量)
可以批量修改,也可以只修改一个。
法一:stream流
/**
* 修改餐品状态
* @param status
* @param ids
* @return
*/
@PostMapping("/status/{status}")
public R<String> updateStatus(@PathVariable Integer status, Long[] ids){
//方法一:使用stream流和lambda表达式
List<Dish> list = Arrays.stream(ids).map((item)->{
Dish dish = dishService.getById(item);
dish.setStatus(status);
return dish;
}).collect(Collectors.toList());
dishService.updateBatchById(list);
return R.success("修改成功");
}
法二:for增强
@PostMapping("/status/{status}")
public R<String> updateStatus(@PathVariable Integer status, Long[] ids){
for (Long id : ids) {
Dish dish = dishService.getById(id);
dish.setStatus(status);
dishService.updateById(dish);
}
return R.success("修改成功");
}
6. 删除菜品(可批量)
/**
* 删除菜品
* @param ids
*/
@Transactional
@DeleteMapping
public R<String> delete(Long[] ids){
for (Long id : ids) {
//删除菜品
dishService.removeById(id);
//删除菜品口味
LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DishFlavor::getDishId,id);
dishFlavorService.remove(queryWrapper);
}
return R.success("删除成功");
}