我记录这篇文章是因为开发过程中,发现上传业务有时候感觉不同平台自己有时一脸懵逼不知道咋样去优化这块业务,不同的后台实现咋样做不同的处理,以下介绍后台实现主要node和java为主,比如:手机端app图片上传,H5页面图片上传,后台管理系统不分离时的图片上传,分离后使用前端框架图片上传这里主要介绍vue,混合框架uni-app图片上传,还有多图片上传优化等
H5 页面文件上传
敬请期待
pc端文件上传(分离)
Layui
+
上传js基于layui
(function(window,layui) {
function uploadImg(url,field, val,nodeSelect,cb) {
layui.use(['upload', 'element', 'layer'], function () {
var $ = layui.jquery
, upload = layui.upload
, element = layui.element
, layer = layui.layer;
if(val) {
$(nodeSelect).attr('src', val); //图片链接(base64)
}
var uploadInst = upload.render({
elem: '#test1'
, url: url
, before: function (obj) {
obj.preview(function (index, file, result) {
$(nodeSelect).attr('src', result); //图片链接(base64)
});
element.progress('demo', '0%'); //进度条复位
layer.msg('上传中', { icon: 16, time: 0 });
}
, done: function (res) {
console.log(res);
//如果上传失败
if (res.code > 0) {
return layer.msg('上传失败');
}
//上传成功的一些操作
val = res.files.file;
cb(val);
}
, error: function () {
//演示失败状态,并实现重传
// var demoText = $('#demoText');
// demoText.html('上传失败 重试');
// demoText.find('.demo-reload').on('click', function () {
// uploadInst.upload();
// });
}
//进度条
, progress: function (n, elem, e) {
element.progress('demo', n + '%'); //可配合 layui 进度条元素使用
if (n == 100) {
layer.msg('上传完毕', { icon: 1 });
}
}
});
});
}
window.uploadImg = uploadImg;
})(window,layui)
pc端文件上传(不分离)
1. node+ejs
- nodejs中在上传文件时,我们通常会使用到Multer中间件用于处理multipart/form-data 类型的表单数据。
cnpm install multer --save
- 视图ejs使用form表单提交,enctype为:
multipart/form-data
表单类型
ejs
node
const express=require("express");
const multer=require('multer');
//初始化上传对象
var upload=multer({dest:'./upload/'});//目录要存在
var fs = require('fs');
var app=express();
app.use("/",upload.single("files"),function(req,res){ //files为input type="file"的name值
var oldFile=req.file.destination+req.file.filename; //指定旧文件
var newFile=req.file.destination + req.file.originalname; //指定新文件
fs.rename(oldFile,newFile,function(err){
if(err){
res.send('上传失败!');
}else{
res.send('上传成功!');
}
});
});
app.listen(8080);
- 上传多个文件
- 首先要在ejs中form的input 加上
multiple
- 使用multer中间的方法 变为
array("files",5)
,通过遍历处理数据
- 首先要在ejs中form的input 加上
- 总结
- 在HTML找中input type="file"需要加上multiple来实现过滤,multiple不写参数则可以读取·所有文件。而在服务端上,我们需要将single()改为array(“name”,num);的形式来接收多个文件的上传请求。最后对他们全部进行重命名。在这之前我们首先看看multer支持哪些文件上传方式:
.single(fieldname) //接受一个以 fieldname 命名的文件。.fields(fields) .array(fieldname[, maxCount]) //接受一个以 fieldname 命名的文件数组。可以配置 maxCount 来限制上传的最大数量。 .fields(fields) //接受指定 fields 的混合文件。fields是一个拥有name和maxCount的数组对象。 .none() //只接受文本域。如果任何文件上传到这个模式,将发生 "LIMIT_UNEXPECTED_FILE" 错误。 .any() //接受一切上传的文件。
- 通过limits来限制上传文件
limits参数var upload=multer({dest:'./upload/',limits:{fileSize: 1024 * 1024 * 20,files: 5}});
Key Description Default fieldNameSize field 名字最大长度 100 bytes fieldSize field 值的最大长度 1MB fields 非文件 field 的最大数量 无限 fileSize 在 multipart 表单中,文件最大长度 (字节单位) 无限 files 在 multipart 表单中,文件最大数量 无限 parts 在 multipart 表单中,part 传输的最大数量(fields + files) 无限 headerPairs 在 multipart 表单中,键值对最大组数 2000 如果你上传的文件超出这些设定,MulterError模块将会启用,该模块在node_modules/multer/lib/multer-error.js上:
2. java + themlef
敬请期待
uni-app上传
-
通过官方文档我们掌握到图片上传核心的api,举个栗子:
正常情况下:
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有//不支持H5
sourceType: ['album', 'camera'], //从相册选择 照相
success: res => {
console.log(res);//
uni.showLoading({
mask: true,
})
uni.uploadFile({
url: 'http:/xxxx/api/common/image/upload', //仅为示例,非真实的接口地址
filePath: res.tempFilePaths[0],
name: 'file', //相当于formData提交key属性,后台可以根据key获取2进制数据
success: (uploadFileRes) => {
//根据后台返回的结果去获取对应的图片路径
let imgUrl = JSON.parse(uploadFileRes.data).data,
},
complete: () => {
uni.hideLoading()
this.hideInputPopup()
}
});
}
});
-
使用混合框架我们要注意选项的参数差异性
[图片上传失败...(image-c47855-1604483474514)]
了解File类型到底是什么?
-
计算机单位之间的转换:
T(TB):我们所说的1个T
G(GB):我们所说的1个G
M(MB):万字节,也就是我们所说的兆
K(KB):千字节
B(Byte):字节 计算机显示的最小单位。
bit:二进制位8bit == 1B(Byte)八个二进制位等于一个字节
微软 计算机厂商
1024B(Byte)= 1K(KB) 1000B(Byte)= 1K(KB)
1024K(KB)= 1M(MB) 1000K(KB)= 1M(MB)
1024M(MB)= 1G(GB) 1000M(MB)= 1G(GB)
1024G(GB)= 1T(TB) 1000G(GB)= 1T(TB) 打印通过uni.chooseImage获取的图片 内容是什么
[图片上传失败...(image-3551bb-1604483474514)]
- H5中uni-app不支持H5压缩图片,那H5咋样进行图片压缩?
// 图片压缩
export function photoCompress(file,w,objDiv){
var ready=new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file);
ready.onload=function(){
var re=this.result;
canvasDataURL(re,w,objDiv)
}
}
// 通过canvas压缩得到base64
export function canvasDataURL(path, obj, callback){
var img = new Image();
img.src = path;
img.onload = function(){
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if(obj.quality && obj.quality <= 1 && obj.quality > 0){
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
}
- 使用uni-app实现图片上传并压缩,并且在提交一步之前不与后台交互,目的用户体验更好上传时不用等待。
核心js方法配合使用 utils.js
// 上传图片(不交互的)
export function showImg() {
return new Promise((resolve, reject) => {
uni.chooseImage({
count: 1, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: res => {
console.log("chooseImage",res)
let _thumbnail = res.tempFilePaths[0];
let _file = res.tempFiles[0];
let _temp = {
blob: _thumbnail,
file: _file
}
resolve(_temp);
}
});
})
}
//上传图片(交互的)
export function uploadImg(filePath) {
return new Promise((resolve, reject) => {
uni.showLoading({
mask: true,
})
uni.uploadFile({
url: uploadUrl,
name: "file",
filePath: filePath,
success: (uploadFileRes) => {
let _thumbnail = JSON.parse(uploadFileRes.data).data;
resolve(_thumbnail)
},
complete: () => {
uni.hideLoading()
// this.hideInputPopup()
}
});
})
}
// 图片压缩
export function photoCompress(file,w,objDiv){
var ready=new FileReader();
/*开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file);
ready.onload=function(){
var re=this.result;
canvasDataURL(re,w,objDiv)
}
}
// 通过canvas压缩得到base64
export function canvasDataURL(path, obj, callback){
var img = new Image();
img.src = path;
img.onload = function(){
var that = this;
// 默认按比例压缩
var w = that.width,
h = that.height,
scale = w / h;
w = obj.width || w;
h = obj.height || (w / scale);
var quality = 0.7; // 默认图片质量为0.7
//生成canvas
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// 创建属性节点
var anw = document.createAttribute("width");
anw.nodeValue = w;
var anh = document.createAttribute("height");
anh.nodeValue = h;
canvas.setAttributeNode(anw);
canvas.setAttributeNode(anh);
ctx.drawImage(that, 0, 0, w, h);
// 图像质量
if(obj.quality && obj.quality <= 1 && obj.quality > 0){
quality = obj.quality;
}
// quality值越小,所绘制出的图像越模糊
var base64 = canvas.toDataURL('image/jpeg', quality);
// 回调函数返回base64的值
callback(base64);
}
}
template
缩略图
jinEdit组件改写
uni.chooseImage({
count: 9, //默认9
sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], //从相册选择
success: async(res) => {
var file = res.tempFiles[0];
//utils.js 压缩返回base64,直接渲染
photoCompress(file, {
quality: 0.3
}, function(base64Codes){
//这里可以一个图片预览 把base64Codes 赋值给img的src即可
console.log(base64Codes);
_this.editorCtx.insertImage({
src: base64Codes, // 此处需要将图片地址切换成服务器返回的真实图片地址
alt: '图片',
success: function(e) {}
});
})
}
})
场景应用:手机端新闻发布