异步上传图片并且图片回显到页面的解决方案
概述
web开发中上传文件,尤其是上传图片功能,实在太普遍,像评论、用户头像等等。可如何优雅的实现异步上传,并且图片显示页面是需要花一点心思来思考的。网上很多诸如:“图片上传插件“”等都是同一种实现思路的。今天介绍两种解决方案,重点是掌握思路,代码实现比较容易。
一、FileReader对象读取文件将图片转Base64
现在先不考虑图片上传,先解决图片回显的方案:第一种回显方案 -- FileReader对象
推荐API文档(中文):https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader
FileReader是IE10以上可以使用的浏览器对象,其可以对文件解析,转成Base64、字符串、字节数组等。
通过<input type="file">选择一张图片,图片回显借助FileReader的readAsDataURL()方法,将图片转成Base64,后用<img src="Base64">可直接显示图片,代码演示如下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>上传演示</title>
<script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
img{max-width: 100px;}
</style>
</head>
<body>
<input type="file" id="upload" accept="image/*">
<div></div>
<script>
$('#upload').on('change', function (e) {
//原生的文件对象
var curFile = this.files[0];
var reader = new FileReader();
//调它的readAsDataURL并把原生File对象传给它,
reader.readAsDataURL(curFile);//base64
//监听它的onload事件,load完读取的结果就在它的result属性里了
reader.onload = function () {
$('div').append($('<img src="' + reader.result + '">'));
}
})
</script>
</body>
</html>
- 页面<input type="file" id="upload">负责选择文件;
- input添加change事件,方法中获取文件对象this.files[0];
- 创建FileReader对象;
- FileReader对象通过readAsDataURL()文件为Base64;
- reader.onload是读取完文件的回调方法;
- 向div元素中添加一个<img>标签,其中的src属性是reader.result(读取到的Base64)
二、异步上传文件
上面第一种方案的图片回显处理完了,接下来要把实际的图片上传到服务器了。上传需要前台和后台共同处理。
2.1前台的文件上传
普通的form表单提交文件需要3样:<input type="file">控件,提交按钮还有<form enctype="multipart/form-data" method="post">。而异步上传文件则需要手动组装表单元素FormData对象,再通过ajax将数据提交到后台,核心代码如下。
<body>
<input type="file" id="upload">
<div></div>
<script>
$('#upload').on('change', function (e) {
//原生的文件对象
var curFile = this.files[0];
// 创建表单对象并将获取的文件对象绑定
var formData = new FormData();
formData.append('file', curFile);
$.ajax({
url: 'http://localhost:8080/upload',
type: 'POST',
data: formData,
// 将表单对象转换成查询字符串形式,默认是 true。
processData: false,
// 内容类型,默认是:"application/x-www-form-urlencoded",此处false将转成二进制
contentType: false,
success: function (res) {
console.log(res);// 后台返回的值
reviewFile(curFile);// 将文件对象读取
}
});
function readerFile(file) {
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
$('div').append($('<img src="'+reader.result+'">'));
}
}
})
</script>
</body>
- 先获取文件对象var curFile = this.files[0];
- 创建表单对象并将添加文件对象var formData = new FormData();formData.append('file', curFile);
- 通过异步方法将表单对象传给后台,后台返回后通过FileReader对象回显图片,当然也可以将回显的方法写在异步之前;
注意:processData: false,contentType: false,这两个属性必须设置false。否则后台不能接收。
2.2 后台接收异步提交的表单请求
后台接收文件不是本文重点,因为后台接收文件的方法很多,此处演示使用Spring Boot快速搭建一个web项目,pox.xml只需要引入spring-boot-starter-web即可(包含了上传等组件)。
后台接收文件的核心方法:
@PostMapping("upload")
@CrossOrigin // 如果涉及跨域则添加此注解
public Object upload(@RequestParam("file") MultipartFile img) {
// 上传的目录windows
String rootDir = "D:\\data\\www\\img";
//String rootDir = "/data/www"; // Linux
// 原始文件名称 如123.jpg
String originalName = img.getOriginalFilename();
// 文件后缀
String suffix = originalName.substring(originalName.lastIndexOf("."));
// 新文件名称 UUID+后缀
String newName = UUID.randomUUID().toString() + suffix;
// 创建一个File对象,通过目录和文件名
File file = new File(rootDir, newName);
// 创建目录
if (!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
try {
img.transferTo(file);// 核心方法 读取文件并写出
} catch (IOException e) {
e.printStackTrace();
}
// 返回创建的文件名
return newName;
}
后台代码不做解释了,比较容易理解,流程就是将文件以UUID重命名存放在指定目录下。要知道Spring通过MultipartFile对象处理文件上传的就可以了。
启动项目演示
至此已经完成第一种异步上传图片,并回显图片到页面,这种方法“上传(ajax)”和“显示(FileReader)”是分开解决的,上传成功与否不影响图片在页面显示。
三、访问上传图片的远程地址显示图片
接下来说下第二种上传显示的思路:
不需要借助FileReader对象,生产环境中,因为文件已经上传到了图片服务器,通过URL地址是可以访问到那张刚刚上传的图片的。所以可以按这种思路来完成“上传后回显”图片的方式,简单清晰。
3.1为了演示,借助nginx来做静态服务器,通过URL地址指向本地的指定文件目录,下面是简单的Nginx做静态服务器的配置。这里仅仅是做演示,意思是通过浏览器访问http://localhost/123.jpg,就是访问本地D:\data\www\img\123.jpg。
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root D:\data\www\img ;// 通过localhost访问到D盘下的指定目录
}
}
3.2后台代码不变,前台代码修改,后台返回新文件名称,前台异步上传成功后指定src属性为远程图片地址即可<img src="远程图片地址">;
<body>
<input type="file" id="upload">
<div></div>
<script>
$('#upload').on('change', function (e) {
//原生的文件对象
var curFile = this.files[0];
var formData = new FormData();
formData.append('file', curFile);
$.ajax({
url: 'http://localhost:8080/upload',
type: 'POST',
data: formData,
processData: false,
contentType: false,
// res是后台返回上传文件的文件名
success: function (res) {
// nginx指向D盘图片目录
$('div').append($('<img src="http://localhost/'+res+'">'));
}
});
})
</script>
通过img标签src属性,即可看出访问的是远程地址来达到了回显图片的方式。
总结
本文两种方式上传回显图片,第一种ajax异步上传和FileReader读取文件显示图片,都是分开来处理的,特点是上传成功与否不影响图片显示,并且可以在异步上传文件前就能将图片显示页面。
第二种是通过异步上传后,页面去加载刚刚上传的那个图片路径来实现图片显示,这种方式图片显示只能等到上传成功后才能加载到图片,显示与上传是分不开的。没有好坏之分,就看你是怎么选择的。只要搞懂两种方案的思路,我想自己也能做出选择了。
扩展:多图片选择:只在input标签中添加multiple属性即可,获取文件对象的时候就不能this.files[0]了,需要遍历this.files对象来获取所有文件对象,当然后台接收也得是个数组或列表。这就由各位同学自己去动手实现吧。今天就到这里,好久没更新了。ps:gif录屏真好使。
(完)
上一篇: 2014年1月底前百度将有大范围更新
推荐阅读