唠嗑部分
上篇文章我们说了使用form表单的input文件域上传文件,上篇文章:
但是现在随着前后端分离的开发方式,这种方式越来越少见了,对于后端工程师来说,接口层并没有多大变化,对于前端工程师、亦或者是干全栈的同学们来说,ajax已经不再陌生,那我们本节就来说说,ajax实现文件上传及文件预览
首先来说FormData与FileReader的使用,都是HTML5新增的API
FormData
FormData 接口提供了一种表示表单数据的键值对 key/value
的构造方式,并且可以轻松的将数据通过XMLHttpRequest.send()方法发送出去,如果发送请求时的编码类型被设为 "multipart/form-data"
,它会使用和表单一样的格式。
构造函数
// 参数传form表单对象,要求表单中的每一项均有name字段,否则无法帮你做收集
var fd = new FormData(form)
常用api
fd.append(key,value); // 如果指定的key不存在则会新增一条数据,如果key存在,则追加到数据末尾
fd.set(key,value); // 如果指定的key存在则会覆盖
fd.get(key); // 返回该key的第一个值
fd.getAll(key); // 返回该key的所有值,数组格式
fd.delete(key); // 删除一项
fd.has(key); // 判断key是否存在,返回布尔值
FileReader
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件内容,使用 File
或 Blob
对象指定要读取的文件或数据。
构造函数
const fr = new FileReader();
常用api
fr.readAsDataURL(file); // 参数是一个文件,将文件读取为一个Base64编码的字符串,通过fr.result获取
fr.onload = () => {}; // 事件,读取过程是异步的,读取完会执行
言归正传
1、创建项目&导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.4.2</version>
<relativePath/>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.cxs</groupId>
<artifactId>ajax-file-upload</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
2、编写前端页面结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ajax-文件上传</title>
<script type="text/javascript" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
</head>
<body>
<div>
<form id="form">
用户名:<input type="text" name="username"/><br/>
密码: <input name="password" type="password"/><br/>
<input id="file" type="file" name="file" style="display: none;"/>
<label for="file">
<img id="img" src="" title="+" width="300" height="150" style="cursor: pointer;"/>
</label>
<button>上传</button>
</form>
</div>
</body>
</html>
3、后端接口部分
@PostMapping("/upload")
public Map<String, Object> upload(User user, @RequestParam("file") MultipartFile file){
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
try {
if (!ObjectUtils.isEmpty(file)) {
// 获取源文件的名字
String originalFilename = file.getOriginalFilename();
if (StringUtils.hasLength(originalFilename)) {
// 进行文件上传
String fullPath = PATH + File.separator + originalFilename;
File f = new File(fullPath);
if (!f.exists()) {
f.createNewFile();
}
file.transferTo(f);
user.setAvatar(fullPath);
result.put("data", fullPath);
result.put("user", user.toString());
}
} else {
result.put("code", 400);
result.put("msg", "文件不能为空!");
}
} catch (IOException e) {
e.printStackTrace();
result.put("code", 500);
result.put("msg", "文件上传失败!");
}
return result;
}
4、文件预览-FileReader的使用
详解请看注释
// 给input框添加change事件,监听文件的改变
inp.addEventListener("change",function(){
// 获取到文件,inp.files是一个集合
const file = inp.files[0];
// 基础校验
if(!file) {
// 点击了取消,将预览置空
img.src = currentPath;
// 清空currentFile
currentFile = undefined;
return;
}
// 文件格式判断,这里只能传图片
if(!file.type.startsWith("image")) return window.alert('请选择图片');
// 给currentFile赋值
currentFile = file;
// 读取文件,进行预览
const fr = new FileReader();
// 将文件读取为一个base64编码
fr.readAsDataURL(file);
// fr读取是一个异步操作,读取完会执行下面函数
fr.onload = () => {
console.log(fr.result)
img.src = fr.result;
}
})
5、文件上传-FormData的使用
Jquery对于ajax的处理说明:
jQuery帮我们做了封装,会将所有请求的请求头设置为application/x-www-form-urlencoded,而文件上传要求是multipart/form-data
此时如果按照jQuery默认的就会出现问题
解决:不让jQuery帮我们设置就可以:contentType:false,告诉jQuery不要设置我请求头里的content-type
jQuery还会帮我们把数据格式转化为key=value的形式
解决:不让jQuery自动格式化数据:processData:false,告诉jQuery别帮我格式化数据
// 表单的提交事件
$("#form").submit(function (e){
// 阻止表单submit事件的默认行为,否则会有个刷新的现象
e.preventDefault()
// 创建formdata,FormData会将form表单中带有name的字段自动处理成每一项
var formData = new FormData(this);
if(!currentFile) return window.alert("请选择文件再上传");
// 发送ajav请求上传
$.ajax({
// 服务器接口地址
url: '/upload',
// 请求方式
type: 'post',
// 参数
data: formData,
// 这两个参数在文件上传时较特殊,详细请看文章描述
contentType : false,
processData : false,
// 成功的回调函数
success : (resp) => {
console.log(resp)
}
})
})
测试&结语
测试如下图
结语
1、本文采用jQuery作为ajax库,axios大家可自行研究(类似)
2、源码获取方式,全栈小白公众号后台回复:文件上传