欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

异步上传图片并且图片回显到页面的解决方案

程序员文章站 2024-01-20 13:23:10
...

概述

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>

异步上传图片并且图片回显到页面的解决方案

  1. 页面<input type="file" id="upload">负责选择文件;
  2. input添加change事件,方法中获取文件对象this.files[0];
  3. 创建FileReader对象;
  4. FileReader对象通过readAsDataURL()文件为Base64;
  5. reader.onload是读取完文件的回调方法;
  6. 向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>
  1. 先获取文件对象var curFile = this.files[0];
  2. 创建表单对象并将添加文件对象var formData = new FormData();formData.append('file', curFile);
  3. 通过异步方法将表单对象传给后台,后台返回后通过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录屏真好使。

(完)