目标
实现小程序端单张图片上传。前端通过formdata将文件数据传递到后端。后端用MultipartFile
类型接收文件数据。
遇到的困难:
微信本身没有FormData
对象,无法使用 new FormData
。经过搜索找到解决办法。微信开放社区 | github(个人认为微信开发者社区中的解决办法更适合键值对的传递,而传文件的话还是用github大神自己写的FormData.js)
环境
后端
javaSpring
前端:
小程序 wxml wxss js @vant-ui
后端接口
@PostMapping("/upload")
public ResponseVO<String> upload(@RequestBody MultipartFile file, @RequestParam FileType fileType) {
return new ResponseVO<>(fileService.upload(file, fileType));
}
前端代码
展示项目的背景是头像展示和更改。
图片上传组件
使用的是@vant 的 van-uploader 可以按需引入。
.wxml
```html
<van-uploader file-list="{{ fileList }}" accept="image" bind:after-read="changeAvatar" bind:delete="deleteAvatar" deletable="{{ true }}" max-count="1">
<view>
<image class="avatar" wx:if="{{portrait}}" src="{{portrait}}" />
<image class="avatar" wx:else="{{portrait}}" src="path/images/user-unlogin.png" />
</view>
</van-uploader>
<!--
file-list 用于图片预览,并不是双向绑定的,需要手动的添加删除
bind:after-read 图片上传后触发
bind:delete 图片删除后触发
slot的地方可以自定义样式,这里我用来展示用户目前的头像
-->
.js
/**
上传图片前处理数据
*/
changeAvatar(e) {
const file = e.detail.file;
console.log(file);
//{size: 856983, type: "image", url: "http://tmp/8OH83lYy8YoH355bbf08b9248c35fc20d92f0c5d6c88.png", thumb: "http://tmp/8OH83lYy8YoH355bbf08b9248c35fc20d92f0c5d6c88.png"}
//图片上传组件并没有获取图片的名字,这里截取一部分做图片命名。如果后端不会重命名的话,可以采取加上时间戳的方式避免名字重复
let _name = file.url.split("\/");
let name = _name[_name.length-1];
name = name.length > 10 ? name.substring(name.length - 9, name.length) : name;
this.setData({
imgFile: file.url,
fileName: name
});
this.setData({
fileList: [file]
});/这里是
that.updataAvatar();//向后端传数据
},
deleteAvatar(e) {
this.setData({
imgFile: "",
fileList: []
});
},
效果
formdata传递
首先下载 https://github.com/zlyboy/wx-formdata 的代码,然后放在util文件夹下。
仓库中的README有使用方法。需要注意以下两点:
- 引入:
const FormData = require('../../utils/formdata/formData')
- append类型:
append()
方法来添加字段调用appendFile()
方法添加文件。
.js
/**
* 上传头像
*/
uploadAvatar() {
let that = this;
let upload = new FormData();
upload.appendFile(
"file", that.data.imgFile, that.data.fileName
);
let data = upload.getData();
console.log(data.buffer);
wx.request({
url: 'http://localhost:9720/file/upload?fileType=PORTRAIT',
method: 'POST',
header: {
'content-type': data.contentType,
token: that.data.account.token
},
data: data.buffer,
success: function (res) {
//上传成功
that.setData({
portrait: res.data.data
});
wx.showModal({
title: '信息',
content: res.data.message,
confirmText: '确认'
}); //showModal
}//success
});
},
成功发送formdata的数据时的请求是这样的
web网页
如果是web端的话使用formdata就简单多了,记录一下。
//element-ui
<el-upload
class="avatar-uploader"
action=""
:auto-upload="false"
accept=".jpg,.jpeg,.png,.JPG,.JPEG"
:show-file-list="false"
:on-change="getImageLocalUrl"
:before-upload="beforeAvatarUpload"
>
<img
v-if="userInfo.portrait"
:src="userInfo.portrait"
class="avatar"
/>
<i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
//script
getImageLocalUrl(file, fileList) {
this.userInfo.portrait = URL.createObjectURL(file.raw);
this.imgFile = file.raw;
this.uploadAvatar();
},
uploadAvatar(){
let upload = new FormData();
upload.append("file", this.imgFile);
this.$axios
.post("/file/upload?fileType=PORTRAIT", upload)
.then(async (res) => {
_this.$message.success({
message: "更新成功!",
duration: 1500,
showClose: true,
});
}).catch((err) => err);
}