前言:
最近开发的一个微信小程序项目需要做一个同时选中三张(或者是多张)图片一起上传到服务端,服务端保存图片资源并保存的功能。发现在微信小程序开发中会有很多场景会使用到多图片上传并保存到的功能,所以我把自己总结的一些方法和完整示例写了下来希望能够帮到有需要的同学。
使用技术:
在这章中将会使用到微信小程序wx.uploadFile(Object object) 和wx.chooseImage(Object object)接口,对图片大小和来源进行上传,后端则使用的.NET WebAPI来接收图片资源文件并保存。
wx.chooseImage() 概述:
从本地相册选择图片或使用相机拍照,详细了解请阅读微信小程序开发文档(https://developers.weixin.qq.com/miniprogram/dev/api/wx.chooseImage.html?search-key=wx.chooseimage)
参数:
属性 | 类型 | 默认值 | 必填 | 说明 |
count | number | 9 | 否 | 最多可以选择的图片张数 |
sizeType | Array.<string> | ['original', 'compressed'] | 否 | 所选的图片的尺寸 |
sourceType | Array.<string> | ['album', 'camera'] | 否 | 选择图片的来源 |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
wx.uploadFile()概述:
将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type
为 multipart/form-data,详细了解请阅读微信小程序开发文档(https://developers.weixin.qq.com/miniprogram/dev/api/wx.uploadFile.html?q=wx.uploadFile)。
参数:
属性 | 类型 | 默认值 | 必填 | 说明 |
url | string | 是 | 开发者服务器地址 | |
filePath | string | 是 | 要上传文件资源的路径 | |
name | string | 是 | 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容 | |
header | Object | 否 | HTTP 请求 Header,Header 中不能设置 Referer | |
formData | Object | 否 | HTTP 请求中其他额外的 form data | |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
废话不多说,上代码:
小程序页面代码:
<view class='form-s2'> <view>门店照片(请选择三张)</view> <view> <view class="weui-uploader__files" id="uploaderFiles"> <block wx:for="{{files}}" wx:key="*this"> <view class="weui-uploader__file" bindtap="previewImage" id="{{item}}" style='margin-top:11px;'> <image class="weui-uploader__img" src="{{item}}" mode="aspectFill" /> </view> </block> </view> <view class="weui-uploader__input-box" style='top:11px;'> <view class="weui-uploader__input" bindtap="chooseImage"></view> </view> </view> </view>
小程序Js代码:
Page({ /** * 页面的初始数据 */ data: { files: [], //门店图片信息,数组图片保存作为数据源 }, , /** * 多图片上传 */ chooseImage: function(e) { var that = this; if (that.data.files.length > 2) { resource.notishi("抱歉最多只允许上传三张图片哟~"); return false; } wx.chooseImage({ count: 3, //默认9张,这里设置三张 sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有 sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有 success: function(res) { wx.showLoading({ title: '上传中,请稍等...', }) // 返回选定照片的本地文件路径列表,tempFilePath可以作为img标签的src属性显示图片 var tempFilePaths = res.tempFilePaths; //多图片上传,tempFilePaths本地图片地址为一个数组,遍历调用服务器图片上传接口即可实现多图保存 for (var i = 0; i < tempFilePaths.length; i++) { console.log('图片地址名称' + tempFilePaths[i]); wx.uploadFile({ url: app.globalData.hostUrl + "/api/PictureUpload/Upload", //此处为实际接口地址 filePath: tempFilePaths[i], //获取图片路径 header: { 'content-type': 'multipart/form-data' }, name: 'upload', success: function(res) { wx.hideLoading(); let Result = JSON.parse(res.data); console.log(Result);//接收返回来的服务器图片地址 if (Result.code == 1) { let picurl = app.globalData.hostUrl + Result.picturePath; console.log(picurl); that.setData({ files: that.data.files.concat(picurl) }); } else { resource.notishi("网络异常,请稍后再试"); } }, fail: function(res) { wx.hideLoading() wx.showToast({ title: '上传失败,请重新上传', icon: 'none', duration: 2000 }) }, }) } } }) }, //图片预览 previewImage: function(e) { wx.previewImage({ current: e.currentTarget.id, // 当前显示图片的http链接 urls: this.data.files // 需要预览的图片http链接列表 })}, })
.NET WebAPI接口服务接收图片资源并保存:
后端使用MultipartMemoryStreamProvider来上传文件,详情如下所示:
using System; using System.IO; using System.Net.Http; using System.Threading.Tasks; using System.Web.Hosting; using System.Web.Http; namespace ShopSite.Controllers { public class FileUploadController : ApiController { /// <summary> /// 图片上传保存 /// </summary> /// <returns></returns> [HttpPost] public IHttpActionResult PictureUpload() { try { var picturePath = ""; const string fileTypes = "gif,jpg,jpeg,png,bmp";//运行上传的图片文件格式 var content = Request.Content;//获取或设置 HTTP 消息的内容(当需要获取HTTP信息是会使用到) const string tempUploadFiles = "/UploadFile/"; //保存路径 var newFilePath = DateTime.Now.ToString("yyyy-MM-dd") + "/"; var memoryStreamProvider = new MultipartMemoryStreamProvider();//获取图片文件流信息 Task.Run(async () => await Request.Content.ReadAsMultipartAsync(memoryStreamProvider)).Wait(); foreach (var item in memoryStreamProvider.Contents) { if (item.Headers.ContentDisposition.FileName == null) continue; var filename = item.Headers.ContentDisposition.FileName.Replace("\"", ""); var file = new FileInfo(filename); //upload fail(判断是否是运行上传的图片格式) if (Array.IndexOf(fileTypes.Split(','), file.Extension.Substring(1).ToLower()) == -1) { return Json(new { code =0,picturePath ="", msg = "不支持上传文件类型" }); } //获取后缀 var extension = Path.GetExtension(filename); var newFileName = Guid.NewGuid().ToString()+extension;//重命名 if (!Directory.Exists(HostingEnvironment.MapPath("/") + tempUploadFiles + newFilePath)) { Directory.CreateDirectory(HostingEnvironment.MapPath("/") + tempUploadFiles + newFilePath); } var filePath = Path.Combine(HostingEnvironment.MapPath("/") + tempUploadFiles + newFilePath, newFileName); picturePath=Path.Combine(tempUploadFiles + newFilePath, newFileName);//图片相对路径 var result = item.ReadAsStreamAsync().Result; using (var br = new BinaryReader(result)) { var data = br.ReadBytes((int)result.Length); File.WriteAllBytes(filePath, data);//保存图片 } } //save successfully return Json(new { code = 1, picturePath = picturePath,msg = "图片上传成功~" }); } catch (Exception ex) { return Json(new { code =0, msg = ex.Message }); } } }
效果图展示(美女哟,嘻嘻):
总结:
其实做完回过头来想想,无论是微信小程序图片上传还是h5 js图片上传原理其实都是差不多,都是通过content-type 为 multipart/form-data 标识,通过http post将图片资源文件以二进制的编码格式传往后台,然后后台获取对应文件流进行数据图片保存。总结的不够到位,有什么没做好的望各位大佬指点。