html
type="file"指定input为文件选择框,accept="image/*"表示文件框可以选择图片,multiple表示可以选择多个文件。
capture拍照
capture='camera'表示图片只能从相机实时抓取,禁止从相册中选择,需要注意的是capture和multiple同时使用时multiple会失效。
onfocus防止键盘弹出
onfocus="this.blur()"表示强制失去焦点,为了防止在某些手机浏览器上点击时会弹出键盘选择。
change事件
var upload = document.getElementById('upload'); upload.addEventListener('change', function() { var file = upload.files[0]; //获取file文件 console.info(file); console.info(file.size); }, false);
file对象
File对象为获取的文件对象,虽然有 getAsBinary()、getAsDataURL()和getAsText三个函数,但这个都是非标准函数,不能使用,需要使用FileReader读取文件。
FileReader
1) readAsArrayBuffer():在返回的result属性中将包含一个ArrayBuffer对象【缓冲数组,是一种用于呈现通用、固定长度的二进制数据的类型】以表示所读取文件的内容。
2) readAsBinaryString():result属性中将包含所读取文件的原始二进制数据。
3) readAsDataURL():result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容,即Base64。
4) readAsText():result属性中将包含一个字符串以表示所读取的文件内容。
图片转base64
var reader = new FileReader(); reader.readAsDataURL(file); //文件读取为base64 reader.onload = function(e) { //e代表事件,可以通过e.target获取FileReader对象然后在获取readAsDataURL读取的base64字符 console.log(e.target.result); ////this代表FileReader,可以用this.result获取读取结果 //预览图片 var img = new Image(); img.src = this.result; $('#previewDIv').append(img); };
URL对象
blob 其实是 h5 表征的 Blob 对象数据, 可以使用Blob对象隐藏真实的资源路径,在一定程度上可以起到数据的加密性,更多的是为了干扰爬虫。
日常使用的一些音频,视频,图片,我们都可以使用其Blob二进制数据流来表征数据,而非使用uri,就像经常用到的image sr 的dataUrl。
var url = URL.createObjectURL(file); var img = new Image(); img.src = url; img.onload = function(e) { window.URL.revokeObjectURL(this.src); //销毁 } console.log(url);
预览前端选择的文件
var img = new Image(); img.width = 200; img.height = 200; img.onload = function(){ window.URL.revokeObjectURL(img.src); //释放通过URL.createObjectURL()创建的URL对象 } img.src = window.URL.createObjectURL(file); //用file对象创建blob协议的URL,用new Blob([file]) $('#preview').append(img);
Blob对象
Blob(binary large object)对象代表了一段二进制数据,就是一个包含只读原始数据的类文件对象。
File接口基于Blob,继承了Blob的功能,并且扩展支持了用户计算机上的本地文件。
Blob构造函数生成文件
var blob = new Blob(["pwstrick"]); //数组中添加DOMString对象 var a = document.createElement("a"); a.href = URL.createObjectURL(blob); //创建URL对象 a.download = "test.txt"; //HTML5新属性,下载url的资源而不是导航,可以设置下载文件名 a.textContent = "下载"; //a标签的文字 document.getElementsByTagName('body')[0].appendChild(a);
Blob构造函数生成图片
var blob = new Blob([file]); //数组中添加表单中获取的file文件 var a = document.createElement("a"); a.href = URL.createObjectURL(blob); //创建URL对象 a.download = "test.jpg"; //HTML5新属性,下载url的资源而不是导航,可以设置下载文件名 a.textContent = "下载"; //a标签的文字 document.getElementsByTagName('body')[0].appendChild(a);
切割blob
//返回文件某一段的blob function segment(file, start, end) { var reader = new FileReader(); reader.onload = function(evt) { console.log(['Read bytes: ', start, ' - ', end].join('')); //console.info(this.result); //文件的某一部分 }; var blob = file.slice(start, end); //返回一个新的Blob对象,它包含有源Blob对象中指定范围内的数据 return reader.readAsBinaryString(blob); //FileReader读取blob对象 } //切割某个文件 var start = 0; //读取起始位置 var chunk = 1024 * 1000; //10KB var end = start + chunk; var size = file.size; //最大位置 while (start < size) { var b = segment(file, start, end); start = end; end = start + chunk; if (end > size) { end = size; } }
FormData
用FormData对象,可以使用键值对来模拟一个完整的表单,然后使用XMLHttpRequest发送这个"表单"。
使用FormData的最大优点是可以异步上传一个二进制文件。
var formData = new FormData(); formData.append("name", "value"); //普通键值对 formData.append("blob", blob); //传递一个blob对象,这里要用定制接口,不然后台保存的就是一个名为blob的文件 formData.append("file", file); //传递一个file对象 var oReq = new XMLHttpRequest(); oReq.open("POST", "./uploadController/upload"); oReq.onloadend = function () { //请求结束时调用(包括成功:onload、失败:onabort、onerror) console.info(oReq.responseText); //打印请求返回结果 var jsondata = JSON.parse(oReq.responseText); //转换为json对象 } oReq.send(formData); //发送表单
移动端图片上传
前端
html
js
$(function () { //拍照完毕时触发input-file的change事件 var sceneImg = document.getElementById("sceneImg"); sceneImg.addEventListener("change",function () { var file = sceneImg.files[0]; //获取到刚才拍照的图片 //预览框中添加预览图片 var img = new Image(); /*img.width = 50; img.height = 50;*/ img.style="width: 50px;height: 50px;margin-top:5px"; img.onload = function(){ window.URL.revokeObjectURL(img.src); //释放通过URL.createObjectURL()创建的URL对象 } img.src = window.URL.createObjectURL(file); //用blobURL的方式回显 $('#preview').append(img); $('#preview').append(" "); /*判断图片路径是否超过指定长度*/ if($('#imgs').val().length>450){ layer.alert("图片以达上线,禁止添加!!!",{title:'提示',offset: '150px',icon: 2}); return false; } /*上传照片*/ var formData = new FormData(); //添加字符串参数,这里是图片即将上传的文件夹 formData.append("pathfolder",'img-'+'${handlercode}'); //添加文件参数,这里也可以用blob formData.append('file', file); var oReq = new XMLHttpRequest(); oReq.open("POST", "./uploadController/upload"); oReq.onloadend = function () { //请求结束时调用(包括成功:onload、失败:onabort、onerror) var jsondata = JSON.parse(oReq.responseText); //解析后端返回的json var imgPath = jsondata.path; var oldimgs = $('#imgs').val(); /*成功后把图片路径加到input框中*/ if(oldimgs.length>0){ $('#imgs').val(oldimgs+","+imgPath); }else { $('#imgs').val(imgPath); } } oReq.send(formData); //提交表单 }); });
后端
package com.gmtx.common.controller; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; /** * UploadController * @author: 秋雨 * 2021-02-01 16:32 **/ @Controller @RequestMapping(value = "/uploadController", method = { RequestMethod.GET,RequestMethod.POST }) public class UploadController { /** * 上传文件 * @param req * @param resp * @return * @throws Exception */ @RequestMapping(value = "/upload", method = {RequestMethod.POST }) public String Upload(HttpServletRequest req, HttpServletResponse resp)throws Exception{ req.setCharacterEncoding("utf-8"); Listfiles = ((MultipartHttpServletRequest) req).getFiles("file"); MultipartFile file = files.get(0); String pathfolder = req.getParameter("pathfolder"); if (file.isEmpty()) { String json = "{\"success\":false,\"message\":\"file is empty!\"}"; resp.getOutputStream().write(json.getBytes("utf-8")); } else { Date time =new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); String dateNowStr = sdf.format(time); //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全 String folderPath = File.separator+"upload"+File.separator+pathfolder+File.separator+dateNowStr; String savePath = req.getSession().getServletContext().getRealPath(folderPath); File fileFolder = new File(savePath); //判断上传文件的保存目录是否存在 if (!fileFolder.exists() && !fileFolder.isDirectory()) { //创建目录 fileFolder.mkdirs(); } //文件保存目录 String filesavepath = savePath+File.separator+file.getOriginalFilename(); //IO流写入 OutputStream outputStream=new FileOutputStream(filesavepath); InputStream inputStream = file.getInputStream(); //FileUtil.copyStream(inputStream, outputStream); byte[] bytes = new byte[1024]; int len = 0; while((len = inputStream.read(bytes))!=-1){ //读取到文件末尾的话可以读到-1 outputStream.write(bytes,0,len); } //flush输出流 outputStream.flush(); //关闭流文件 inputStream.close(); outputStream.close(); //图片存储路径(web用) String webPath = folderPath+File.separator+file.getOriginalFilename(); //因为URLEncoder.encode会把空格改为+号,要手动把加号改为%20 webPath = URLEncoder.encode(webPath,"utf-8").replace("+", "%20"); String json = "{\"success\":true,\"message\":\"文件上传成功!\",\"path\":\""+ webPath +"\"}"; resp.resetBuffer(); resp.setContentType("text/html;charset=UTF-8"); resp.getOutputStream().write(json.getBytes("utf-8")); resp.getOutputStream().flush(); } return null; } }