本篇教程技术栈:springBoot(Java后端)+ 微信小程序。完整的图片上传教程。
页面截图,点击图片右上角按钮可以删除图片。
1、图片上传需要使用wx.uploadFile(Object object)接口
官方示例代码如下:
wx.chooseImage({
success(res) {
const tempFilePaths = res.tempFilePaths
wx.uploadFile({
url: 'https://example.weixin.qq.com/upload', // 仅为示例,非真实的接口地址
filePath: tempFilePaths[0],
name: 'file',
formData: {
user: 'test'
},
success(res) {
const data = res.data
// do something
}
})
}
})
参数说明如下图所示:
有三个是必填的参数,url、filePath、name。其中name的需要和Java后台的保持一致,切记!!!本历程还使用了formData参数,上传文本数据。
2、小程序完整代码如下:
①js文件
// pages/lost-found/lost-found.js
var api = require("../../utils/api.js");
var that;
var app = getApp();
var adds = {};
Page({
data: {
image_width: 0,
nickName: "",
avatarUrl: "",
loading: false,
images: [],
urlArr: [],
publishList: ["拾到物品", "丢失物品"],
reasonList: ["卡类", "钥匙", "数码产品", "U盘", "其他物品"],
idP: null,
idR: null,
choseReason: '',
formdata: '',
content: '',
tel: "",
extracontent: '',
},
onLoad: function () {
that = this;
wx.getSystemInfo({
success: function (res) {
// console.log(res);
that.setData({
image_width: (res.windowWidth / 4) - 10
});
}
});
},
bindSubmit: function (e) {
// 判断是否正在上传图片
// if (that.data.loading) {
// return;
// }
var reason = that.data.choseReason;
var content = e.detail.value.content;
var nickName = app.globalData.wxuserInfo.nickName;
var publish = that.data.chosePublish;
var tel = e.detail.value.tel;
if (!reason) {
wx.showToast({
title: '请选择物品类型',
image: '../../images/more/about.png',
duration: 2000
})
}
else if (!content) {
wx.showToast({
title: '请填写拾到/丢失地点',
image: '../../images/more/about.png',
duration: 2000
})
} else if (!tel) {
wx.showToast({
title: '请填写正确的联系方式',
image: '../../images/more/about.png',
duration: 2000
})
}
else {
nickName = app.globalData.wxuserInfo.nickName;
publish = that.data.chosePublish;
reason = that.data.choseReason;
content = e.detail.value.content;//拾到或者丢失地点
that.setData({
content: e.detail.value.content,
extracontent: e.detail.value.extracontent,
tel: e.detail.value.tel
})
this.uploadViews()
}
},
chosePublish: function (e) {
var index1 = e.currentTarget.dataset.index; //获取自定义的ID值
this.setData({
idP: index1,
chosePublish: that.data.publishList[index1]
})
console.log(that.data.idP);
// console.log(that.data.chosePublish);
},
choseReason: function (e) {
var index2 = e.currentTarget.dataset.index; //获取自定义的ID值
this.setData({
idR: index2,
choseReason: that.data.reasonList[index2]
})
},
upImg: function () {
var that = this;
wx.chooseImage({
count: 9, // 默认9
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: function (res) {
wx.showNavigationBarLoading()
that.setData({
loading: false
})
var urlArr = that.data.urlArr;
// var urlArr={};
var tempFilePaths = res.tempFilePaths;
var images = that.data.images;
// console.log(tempFilePaths);
that.setData({
images: images.concat(tempFilePaths),
});
}
})
console.log(that.data.urlArr)
},
uploadViews: function () {
var that = this
if (this.data.images.length == 0) {
wx.request({
url: api.lostfoundNoImgUrl,
data: {
nickName: app.globalData.wxuserInfo.nickName,
publish: that.data.chosePublish,
reason: that.data.choseReason,
content: that.data.content,
extracontent: that.data.extracontent,
tel: that.data.tel,
}, //表单数据
method: 'POST',
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
name: 'views',
success: function (res) {
console.log(res);
if (res.statusCode == 200) {
wx.showToast({
title: '反馈成功,感谢!',
icon: "success",
duration: 1500,
})
} else {
wx.showToast({
title: '提交失败',
icon: "fail",
duration: 1500,
});
that.setData({
reason: '',
content: '',
})
}
setTimeout(function () {
wx.switchTab({
url: '../index/index',
})
}, 2000)
},
})
} else {
for (var i = 0; i < this.data.images.length; i++) {
wx.uploadFile({
url: api.lostfoundUrl,
filePath: that.data.images[i],
name: 'lostfound',
formData: {
'nickName': app.globalData.wxuserInfo.nickName,
'publish': that.data.chosePublish,
'reason': that.data.choseReason,
'content': that.data.content,
'extracontent': that.data.extracontent,
'tel': that.data.tel,
},
header: {
'content-type': 'multipart/form-data'
},
success: function (res) {
console.log(res)
if (res.statusCode == 200) {
wx.showToast({
title: '反馈成功,感谢!',
duration: 1500
});
} else {
wx.showToast({
title: '提交失败',
icon: "fail",
duration: 1500,
});
}
setTimeout(function () {
wx.switchTab({
url: '../index/index',
})
}, 2000)
}
})
this.setData({
adds: {},
})
}
}
this.setData({
adds: {},
images: ''
})
},
// 获取本地显示的图片数组
delete: function (e) {
var index = e.currentTarget.dataset.index;
var images = that.data.images;
var urlArr = that.data.urlArr;
urlArr.splice(index, 1);
images.splice(index, 1);
that.setData({
images: images,
urlArr: urlArr
});
console.log(that.data.urlArr)
},
// 检查字符串是否为合法手机号码
isPhone: function (str) {
var reg = /^1(3|4|5|7|8|9)\d{9}$/;
if (reg.test(str)) {
return 1;
} else {
return -1;
}
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
代码中,分了两种情况,带图片上传和不带图片上传。默认选择图片上传数量为9张,修改count的值就可以了。
②wxml文件
<view class="page">
<form bindsubmit="bindSubmit">
<view class="head">
<view class="headText">* 请选择发布类型</view>
</view>
<view class="chosePublish">
<view class="reasonItem" wx:for="{{publishList}}" data-index="{{index}}" bindtap="chosePublish" style="{{index==idP?'background-color: #2782D7;color:#fff':' background-color: #efefef;' }}">
<view bindtap="falseInformation">{{item}}</view>
</view>
</view>
<view class="remark">
<view class="headText">* 请选择物品类型</view>
</view>
<view class="choseReason">
<view class="reasonItem" wx:for="{{reasonList}}" data-index="{{index}}" bindtap="choseReason" style="{{index==idR?'background-color: #2782D7;color:#fff':' background-color: #efefef;' }}">
<view bindtap="falseInformation">{{item}}</view>
</view>
</view>
<view class="remark">
<text class="remark-title">* 拾到/丢失地点:</text>
<textarea name="content" class="inputRemark" bindblur="bindTextAreaBlur" maxlength="500" placeholder="请简单说明" />
</view>
<view class="remark">
<text class="remark-title">* 额外说明:<text style="color:#737373;font-size:30rpx;">(若无可不填)</text></text>
<textarea name="extracontent" class="inputRemark" bindblur="bindTextAreaBlur" maxlength="500" placeholder="如有其他情况,可简要说明" />
</view>
<view class="remark_tel">
<text class="tel-title">* 联系方式:</text>
<input name="tel" class="input" type='number' maxlength="100" value='{{tel}}' placeholder="QQ/微信/手机号" />
</view>
<text class="imageTitle">* 相关图片:<text style="color:#737373;font-size:30rpx;">(若无则可不上传)</text></text>
<view class="gallery">
<view class="itemImage" wx:for="{{images}}">
<!-- <image class="thumb" data-current="{{item}}" style="width: {{2*image_width}}rpx; height: {{2*image_width}}rpx" src="{{item.url}}" /> -->
<!-- 默认数组的当前项的下标变量名默认为 index,数组当前项的变量名默认为 item -->
<image class="thumb" data-current="{{item}}" style="width: {{2*image_width}}rpx; height: {{2*image_width}}rpx" src="{{item}}" />
<image class="delete" src="../../images/more/deleteImage.png" data-index="{{index}}" bindtap="delete"></image>
</view>
<image class="thumb" style="width: {{2*image_width}}rpx; height: {{2*image_width}}rpx" src="../../images/more/upload.png" bindtap="upImg" />
</view>
<button class="submitButton" formType="submit">发布</button>
</form>
</view>
③wxss文件
page{
height: 100%;
}
.page{
font-family: 'PingFang SC', 'Helvetica Neue', Helvetica, 'Droid Sans Fallback', 'Microsoft Yahei', sans-serif;
height: 100%;
background-color: #efefef;
}
.head{
background-color: #fff;
}
.headText{
padding: 20rpx 0rpx 0rpx 20rpx;
color: #2782D7;
}
.chosePublish{
padding: 10rpx 0rpx 30rpx 0rpx;
display: flex;
flex-direction: row;
background-color: #fff;
}
.choseReason{
padding: 10rpx 0rpx 30rpx 0rpx;
display: flex;
flex-direction: row;
background-color: #fff;
/* display:inline-block; */
}
.reasonItem{
margin:15rpx;
padding: 15rpx;
background-color: #efefef;
float:left;
display:inline;
color: #7a7a7a;
}
.remark{
margin-top: 20rpx;
background-color: #fff;
}
.remark_tel{
display: flex;
margin-top: 20rpx;
height: 80rpx;
line-height: 80rpx;
align-items: center;
background-color: #fff;
}
.tel-title{
float: left;
padding-left: 20rpx;
height: 60rpx;
line-height: 60rpx;
width: 40%;
color: #2782D7;
}
.input {
height: 60rpx;
line-height: 60rpx;
padding-left: 10rpx;
}
.remark-title{
display: flex;
color: #2782D7;
padding: 30rpx 0rpx 30rpx 20rpx;
}
.inputRemark{
padding: 0rpx 20rpx 0rpx 20rpx;
width: 90%;
height: 80rpx;
}
.imageTitle{
display: flex;
color: #2782D7;
margin-top: 20rpx;
padding: 30rpx 0rpx 30rpx 20rpx;
background-color: #fff;
}
.gallery {
display: flex;
flex-direction: row;
justify-content: flex-start;
flex-wrap: wrap;
background-color: #fff;
}
/*每张图片所占容器*/
.itemImage {
position: relative;
}
/*小图片*/
.thumb {
margin: 10rpx;
position: relative;
}
/*删除按钮*/
.delete {
position: absolute;
height: 40rpx;
top: 0rpx;
right:0;
width: 40rpx;
}
.delete image {
position: absolute;
width: 30rpx;
height: 30rpx;
}
.photo{
text-align: center;
margin: 30rpx 0rpx 20rpx 0rpx;
}
.submitButton{
width:80%;
height:90rpx;
background-color:#2782D7;
border-radius:30px;
color:#fff;
margin: auto;
margin-top: 30rpx;
margin-bottom: 50rpx;
display:flex;
justify-content:center;
align-items:center;
}
3、Java后端,springboot搭建
controller文件
package com.ahu.controller;
import com.ahu.Repository.LostFoundApplyRepository;
import com.ahu.domain.LostFoundApply;
import com.ahu.exception.ExceptionManager;
import com.ahu.utils.Response;
import io.swagger.annotations.ApiOperation;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author R
* UPLOAD请求修改为POST请求
* 可支持图片上传 2018-12-5 【xrq】
*/
@RestController
@RequestMapping("/v1")
public class UploadController {
private final ExceptionManager exceptionManager;
private final LostFoundApplyRepository lostFoundApplyRepository;
private Logger logger = Logger.getLogger(UploadController.class);
@Autowired
public UploadController(ExceptionManager exceptionManager, LostFoundApplyRepository lostFoundApplyRepository) {
this.userInfoRepository = userInfoRepository;
this.exceptionManager = exceptionManager;
this.lostFoundApplyRepository=lostFoundApplyRepository;
}
@Transactional
@ApiOperation(value = "失物招领上传无图")
@RequestMapping(value = "lostfoundNoImg", method = RequestMethod.POST)
public Response lostFoundInfo(
@RequestParam(value = "nickName") String nickName,
@RequestParam(value = "publish") String publish,
@RequestParam(value = "reason") String reason,
@RequestParam(value = "content") String content,
@RequestParam(value = "extracontent") String extracontent,
@RequestParam(value = "tel") String tel
) {
Date now = new Date();
LostFoundApply lostFoundApply = new LostFoundApply();
lostFoundApply.setNickName(nickName);
lostFoundApply.setPublish(publish);
lostFoundApply.setReason(reason);
lostFoundApply.setContent(content);
lostFoundApply.setExtracontent(extracontent);
lostFoundApply.setTel(tel);
lostFoundApply.setApplytime(now);
lostFoundApplyRepository.save(lostFoundApply);
return new Response().success();
}
@ResponseBody
@ApiOperation(value = "失物招领上传多图")
@RequestMapping(value = "/lostfound")
public String lostFoundInfo(
HttpServletRequest request,
HttpServletResponse response,
@RequestParam(value = "nickName") String nickName,
@RequestParam(value = "publish") String publish,
@RequestParam(value = "reason") String reason,
@RequestParam(value = "content") String content,
@RequestParam(value = "extracontent") String extracontent,
@RequestParam(value = "tel") String tel
@RequestParam(value = "lostfound") MultipartFile file
) throws IOException {
request.setCharacterEncoding("UTF-8");
BufferedOutputStream stream = null;
logger.info("file:" + file);
String nickName=request.getParameter("nickName");
String publish=request.getParameter("publish");
String reason=request.getParameter("reason");
String content=request.getParameter("content");
String extracontent=request.getParameter("extracontent");
String tel=request.getParameter("tel");
logger.info("nickName:" + nickName);
Date now = new Date();
LostFoundApply lostFoundApply = new LostFoundApply();
lostFoundApply.setNickName(nickName);
lostFoundApply.setPublish(publish);
lostFoundApply.setReason(reason);
lostFoundApply.setContent(content);
lostFoundApply.setExtracontent(extracontent);
lostFoundApply.setTel(tel);
lostFoundApply.setApplytime(now);
lostFoundApplyRepository.save(lostFoundApply);
if(!file.isEmpty()) {
String fileName = file.getOriginalFilename();
String path = null;
String type = null;
type = fileName.indexOf(".") != -1 ? fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length()) : null;
logger.info("图片初始名称为:" + fileName + " 类型为:" + type);
if (type != null) {
logger.info("成功获取照片");
if ("GIF".equals(type.toUpperCase())||"PNG".equals(type.toUpperCase())||"JPG".equals(type.toUpperCase())) {
// 项目在容器中实际发布运行的根路径
// String realPath = request.getSession().getServletContext().getRealPath("/");
// 自定义的文件名称
// String trueFileName = String.valueOf(System.currentTimeMillis()) + fileName;
String trueFileName = String.valueOf(nickName) + fileName;
// 设置存放图片文件的路径
// path = realPath + "uploads\\" + trueFileName;
path="C:\\java\\LostFound\\"+ trueFileName;
logger.info("存放图片文件的路径:" + path);
file.transferTo(new File(path));
logger.info("文件成功上传到指定目录下!");
}else {
logger.info("不是我们想要的文件类型,请按要求重新上传");
return "error";
}
}else {
logger.info("文件类型为空");
return "error";
}
}
else {
logger.info("没有找到相对应的文件");
return "error";
}
return "success";
}
}
以上是完整的多图片教程,感兴趣的可以一起交流学习啊