- 【文件系统】Vue+SpringBoot模拟文件系统
- 0. 相关知识预告
- 1. 展示文件列表模拟
- 1.1 前端
- 1.1.1 展示样式介绍
- 1.1.2 异步访问接口
- 1.2 后端SpringBoot
- 1.2.1 Controller
- 1.2.2 Service
- 1.3 效果展示
- 2. 新建文件夹模拟
- 2.1 前端
- 2.2 后端
- 2.2.1 Controller
- 2.2.2 Service
- 2.3 效果展示
- 3. 上传文件模拟
- 3.0 form-data和multipart
- 3.1 前端
- 3.2 后端
- 3.2.1 Controller
- 3.2.2 Service
- 3.2.3 springboot的yaml配置
- 3.2.4 重点!MultipartFileUtil工具类
- 3.3 效果展示
- 4. 问题解决总结
- Vue Cli2
- ElementUI
- SpringBoot
- MultipartFile 【form-data】
使用Vue Cli2 + ElementUI
1.1.1 展示样式介绍- 使用el-table展示列表,关键属性是 :data 绑定里面所有行数据【tableData是自定义的一个变量】
- el-table只需要我们设计表头,数据会根据我们定义的一个数组变量内容自动加载,但只有加载el-table有的字段
- 使用相关标签是为了自定义表头,相关样式可以去elementUI官网学习。
效果如下:
代码如下:【值得注意的就是min-width=100%,很好用】
1.1.2 异步访问接口文件名 点击上传 修改时间 大小
- 参数方面直接传入,这样是属于body传入,参数以json串形式传过去,一定要注意这里。
- 因为post还可以通过query传入,和get一样拼接在地址后面。
- 后端对于两种传参的处理是不一样的。
this.$http.post("/file/showAllFiles", {
curUrl: "\d\c",
uid: 9
}).then((res) => {
this.tableData = res.data;
});
1.2 后端SpringBoot
1.2.1 Controller
- post映射指定
- @ResponseBody表示该控制器自动将结果转为json串异步返回
- 参数!!!重中之重。通过map并指定body来接收前端的json串,要么你就弄一个实体对象接收比如Student对象。千万不能用【@RequestParam(“curUrl”) String curUrl】这样接收,这样只允许post请求中的query式参数,所以如果用了RequestParam,即使前端请求成功,后端也拿不到任何数据。因为这样spring就不认json串。
- 注意,需要前端传参uid,访问用户自身专属的文件夹
- 提前把前端传的curUrl相对路径转换为本地绝对路径
@PostMapping("/showAllFiles")
@ResponseBody
public List showAllFiles(@RequestBody Map map) {
String localUrl = store + map.get("uid") + map.get("curUrl");
System.out.println(localUrl);
List res = fileService.showAllFiles(localUrl);
return res;
}
1.2.2 Service
- 大体通过java导入的File包进行处理
- File包能够直接访问本地文件夹,直接获取文件列表
- 我还需要文件的大小,文件的最后修改时间,这些都可以直接获取
- 注意 file.length() 就是文件的大小了
@Override public List1.3 效果展示showAllFiles(String curUrl) { File dir = new File(curUrl); //先判断文件夹是否存在 if(!dir.exists()) { System.out.println("目录不存在"); return null; } //获取文件列表 File[] fileList = dir.listFiles(); //FileInfo是我自定义的一个实体类,把文件中我需要的信息注入作为一个单位返回 List res = new ArrayList<>(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); for(File file : fileList) { //如果是目录,不加入大小,默认“-” if(file.isDirectory()) { res.add(new FileInfo(file.getName()," ", "-", df.format(new Date(file.lastModified())), 1)); }else { String name = file.getName(); //得到的结果是B,字节 double len = Double.valueOf(file.length()); String size = ""; if(len < 1024) { size = "" + String.format("%.2f", len) + "b"; }else if(len >= 1024 && len < 1048576) { size = "" + String.format("%.2f", len/1024) + "kb"; }else if(len >= 1048576 && len < 1073741824) { size = "" + String.format("%.2f", len/1048576) + "mb"; } res.add(new FileInfo(name, name.substring(name.lastIndexOf(".")+1), size, df.format(new Date(file.lastModified())), 0)); } } } return res; }
-
访问用户9的dca位置
-
刷新页面,渲染vue组件时自动请求showAllFiles接口
-
成功访问
前端直接提供一个按钮去访问对应接口就行,这里不演示。
2.2 后端 2.2.1 Controller- 同理接收body参数,所以用map和RequestBody
- 需要知道是哪位用户(uid)在哪里新建(curUrl),找到对应的本地路径
@PostMapping("/newFolder")
@ResponseBody
public Integer newFloder(@RequestBody Map map) {
String localUrl = store + map.get("uid") + map.get("curUrl");
int res = fileService.newFolder(localUrl);
return res;
}
2.2.2 Service
- 调用Files的静态方法创建文件夹
- 成功返回1,失败返回0
@Override
public Integer newFolder(String localUrl) {
//创建本地文件夹,curUrl应该包含name
try{
Files.createDirectories(Paths.get(localUrl));
return 1;
}catch (IOException e){
e.printStackTrace();
return 0;
}
}
值得注意的是:我们需要在注册的时候,先为当前注册成功的用户创建一个专属文件夹。
2.3 效果展示-
模拟接口
-
查看结果【创建成功】
这里要提醒,需要学习form-data和multipart
3.0 form-data和multipartenctype:一个html表单的post请求过程中enctype【中文是编码方式】有三种类型
Content-Type:用于定义用户的浏览器或相关设备如何显示将要加载的数据,或者如何处理将要加载的数据
-
application/x-www-urlencoded
- 编码方式是ASCII
- 是最普通的post编码,数据会被编码到body中传输
- 表单默认是这个
-
multipart/form-data【其实了解他是个传文件的就差不多了】
-
是基于post方法来传递二进制数据的,一般能用来传递文件
-
如图,解释一下,每一行的一个------WebKitFormBoundarynRpsHcUvTeBqpdsH是一个boundary,是可以自定义的,是一个分隔符,你就当他用来分隔各个参数的就行了,有头有尾。
-
参数名与参数值之间会有两行换行,这是官方规定的格式,照着了解就行。
-
整体格式总结
--分隔符(boundary)[换行] Content-Disposition: form-data; name="参数名"[换行] [换行] 参数值[换行] --分隔符(boundary)[换行] Content-Disposition: form-data; name="图片名"; filename="图片文件名"[换行] Content-Type: 类型[换行] [换行] 图片文件的二进制内容[换行] --分隔符(boundary)--
-
- text-plain
- 传递的数据是文本数据,既然是文本,浏览器不会做过多处理。
使用Vue Cli2 + ElementUI
- 使用el-upload进行用户本地文件选取以及自动上传
- 注意使用multiple,不然一个用户只能传一个文件
- 注意也不要添加limit参数
- 默认就是自动上传
- 这里比较关键是data是能传入额外参数,而我们后端需要知道uid和当前路径
- 注意这里使用的是el组件的action,data是属于query参数,直接拼在url后的,后端能直接用@RequestParam
点击上传
- 效果如下:
- 选择文件上传即可。
- 不多说了
- 前端data是属于query参数,直接拼在url后的,后端能直接用@RequestParam
@PostMapping("/uploadFile")
@ResponseBody
public Integer uploadFile(@RequestParam("curUrl") String curUrl, @RequestParam("uid") Integer uid,@RequestParam("file") MultipartFile file) {
String localUrl = store + uid + curUrl;
fileService.uploadFile(file, localUrl);
return 1;
}
3.2.2 Service
- 这里我封装了一个工具类,待会介绍
@Override
public Integer uploadFile(MultipartFile file, String curUrl) {
MultipartFileUtil.addFile(file, curUrl);
return 1;
}
3.2.3 springboot的yaml配置
- 对spirngboot的application.yaml或者其他配置文件都好,配置multipart相关参数
- 不设置大小,默认1m作为单个文件上传上限
spring:
# web处理multipart请求懒加载
servlet:
multipart:
resolve-lazily: true
#设置单个文件大小,单位MB和KB都可以
max-file-size: 1000MB
#设置总上传的数据大小,单位MB和KB都可以
max-request-size: 10000MB
tomcat:
max-swallow-size: 100MB
3.2.4 重点!MultipartFileUtil工具类
-
比较重要的就是获取multipartFile的文件名file.getOriginalFilename();
-
剩下考察你对文件IO流熟不熟悉,这里采用一个手动缓存读写。
-
毕竟都是二进制而已,直接读写即可。
-
源码,可以直接复制使用
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
public class MultipartFileUtil {
public static void addFile(MultipartFile file,String uri){
OutputStream outputStream = null;
InputStream inputStream = null;
String fileName = null;
try {
inputStream = file.getInputStream();
fileName = file.getOriginalFilename();
//log.info("fileName="+fileName);
} catch (IOException e) {
e.printStackTrace();
}
try {
// 2、保存到临时文件
// 1K的数据缓冲
byte[] bs = new byte[1024];
// 读取到的数据长度
int len;
// 输出的文件流保存到本地文件
File tempFile = new File(uri);
if (!tempFile.exists()) {
tempFile.mkdirs();
}
//跨平台写法,windows和linux都适用
outputStream = new FileOutputStream(tempFile.getPath() + File.separator + file.getOriginalFilename());
// 开始读取和写入os
while ((len = inputStream.read(bs)) != -1) {
outputStream.write(bs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 完毕,关闭所有链接
try {
outputStream.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.3 效果展示
-
前端选择文件,确定后自动上传
-
本地查看文件是否下载成功【成功下载到本地】
-
刷新页面
-
el-table的一个min-width=100%使用解决表头问题
-
@RequestParam 或者 直接参数对应需要前端发送的请求参数是query参数【1对1】
-
如果前端请求参数是body参数【json串】,后端要使用@RequestBody,配合map或者实体类进行接收
-
file.length是文件大小
-
前后端对接的时候上传文件使用multipart/form-data,就是通过二进制流传递文件,el-upload能通过:data去传递额外参数
-
多使用工具类封装
-
通过配置文件处理multipart文件上传大小限制
-
搞文件系统当然要想到用File包



