唠嗑部分
上篇文章我们说了使用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、源码获取方式,全栈小白公众号后台回复:文件上传