🚀 优质资源分享 🚀
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
🧡 Python实战微信订餐小程序 🧡 | 进阶级 | 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。 |
💛Python量化交易实战💛 | 入门级 | 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统 |
瑞吉外卖实战项目全攻略——第四天
该系列将记录一份完整的实战项目的完成过程,该篇属于第四天
案例来自B站黑马程序员Java项目实战《瑞吉外卖》,请结合课程资料阅读以下内容
该篇我们将完成以下内容:
- 文件上传下载
- 新增菜品
- 菜品信息分页查询
- 修改菜品
文件上传下载
由于是第一次接触文件上传下载,我们分为五个小阶段讲解
文件上传介绍
文件上传,也称为upload,是指将本地图片,视频,音频等文件上传到服务器上,可以供其他用户浏览下载的过程
首先我们介绍文件上传对前端的要求:
- 以POST方法提交数据
- 采用Multipart格式上传文件
- 使用input的file空间上传
尽管前端组件库提供了相应的上传组件,但这些组件底层仍旧采用上述要求的格式构造
然后我们介绍文件上传在后端的实现:
- 通常采用Apache的两个组件:commons-fileupload 和 commons-io
目前我们的Spring框架在Spring-web包下对文件上传进行了封装,简化了服务端代码
我们只需要在Controller中的方法声明一个MultipartFile类型的参数即可接收上传的数据
文件下载介绍
文件下载,也称为download,是指将文件从服务器传输到本地计算机的过程
通过浏览器进行文件下载,通常有两种表现形式:
- 以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录
- 直接在浏览器中打开
通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写回浏览器的过程
文件上传代码实现
测试用例:
- 资料中为我们提供了一个文件上传下载的示例页面:upload.html
- 可以复制在backend/page/demo下,在我们的代码实现过程中进行调试
我们先来思考一下文件上传的逻辑:
- 我们会获得一个文件File,但这个文件是临时文件,所以我们需要将他储存在电脑中
- 我们的储存位置需要固定,但是这个文件的名称和后缀名需要重新书写,但还要保证名称随机不会重复,后缀名和原文件相同
接下来我们正式开始文件上传代码的实现:
- 书写一个CommonController服务层并构造基本框架:
package com.qiuluo.reggie.controller;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.CoyoteOutputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
/**
* 下载操作
* @param MultipartFile file 是文件上传的唯一必备代码,代表上传的数据
* 注意:file只是一个临时文件,当我们的request请求结束时,file也会消失,所以我们需要将它保存起来
* @return
*/
@PostMapping("/upload")
public Result upload(MultipartFile file){
// 我们可以直接记录日志查看是否收集到file
log.info(file.toString());
}
}
- 书写内部代码,阐明书写思路:
package com.qiuluo.reggie.controller;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.CoyoteOutputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
@Value("${reggie.path}")
private String BasePath;
/**
* 下载操作
* @param file 注意需要与前端传来的数据名一致
* @return
*/
@PostMapping("/upload")
public Result upload(MultipartFile file){
// 由于我们的file是临时文件,我们需要将该文件保存在计算机上
try {
// 这个方法可以转载文件到指定目录
file.transferTo(new File("D:/hello.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
// 注意:我们需要返回文件名,因为我们还需要让图片回显,回显就需要再次传入文件名来查询文件
return Result.success(fileName);
}
}
- 在yaml配置文件中书写全局变量,使存放路径固定:
# 我们定义了一个reggie.path的参数来存放我们存放文件的地址
reggie:
path: E:\imgs\
- 回到主函数中书写代码:
package com.qiuluo.reggie.controller;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.CoyoteOutputStream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.UUID;
/*
目前我们的文件存放已经有了固定的位置
但是我们的文件名以及后缀文件名还没有获得,我们将把它们变为动态的
*/
@Slf4j
@RestController
@RequestMapping("/common")
public class CommonController {
// 定义主路径
@Value("${reggie.path}")
private String BasePath;
/**
* 下载操作
* @param file 注意需要与前端传来的数据名一致
* @return
*/
@PostMapping("/upload")
public Result upload(MultipartFile file){
// 注意:file只是一个临时文件,当我们的request请求结束时,file也会消失,所以我们需要将它保存起来
// 这个方法可以获得文件的原名称,但不推荐设置为文件名保存(因为可能出现重复名称导致文件覆盖)
String originalFilename = file.getOriginalFilename();
// 将原始文件的后缀截取下来
String substring = originalFilename.substring(originalFilename.lastIndexOf("."));
// UUID生成随机名称,文件名设置为 UUID随机值+源文件后缀
String fileName = UUID.randomUUID().toString() + substring;
// 判断文件夹是否存在