微信小程序上传图片至服务器Springboot
-
需求:通过微信小程序上传图片到服务器,保存至服务器。
-
实现
- Wxml
<button bindtap="choose">选择图片</button>
- js
choose:function(){ console.log(1) wx.chooseImage({ count: 1, sizeType:["compressed","original"], sourceType:["album","camera"], success:function(res){ console.log(res) const filePath = res.tempFilePaths[0]; wx.uploadFile({ filePath: filePath, name: "123", url: 'http://xxxx:8080/upload', header:{'Content-Type':'application/x-www-form-urlencoded'}, method:'post', success:function(res){ console.log(res) }, fail:function(res){ console.log(res) } }) } }) }
- uploadController
package com.example.demo; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; @RestController public class UpLoadController { @RequestMapping("/upload") public Map<String,String> upload(@RequestParam("file") MultipartFile file ){ Map<String,String> resultMap = new HashMap<>(); String path = "/Users/lingg/Desktop/"; String fileName = file.getOriginalFilename(); String suffixName = fileName.substring(fileName.indexOf(".")); fileName = UUID.randomUUID()+suffixName; System.out.println("fileName"+fileName); System.out.println("fileType:"+suffixName); File targetFile = new File(path); if(!targetFile.exists()){ targetFile.mkdir(); } File saveFile = new File(targetFile,fileName); try{ file.transferTo(saveFile); System.out.println("上传成功"); String path1 = path+fileName; System.out.println(path1); resultMap.put("result","success"); resultMap.put("path",path1); } catch (IOException e) { e.printStackTrace(); System.out.println("执行失败"); resultMap.put("result","failed"); resultMap.put("path","null"); } return resultMap; } }
- application.properties
spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=100MB
第一步在本地进行测试,使用Postman进行测试:
url:http://localhost/upload
form-data:
file:选择本地文件
返回结果:
{
"result": "success",
"path": "/Users/liushanlin/Desktop/123071ed-27d2-4367-b451-1e02d5432893.jpeg"
}

已经可以看到图片成功保存在本地:测试成功!

第二步:部署至服务器,同样使用postman进行测试
启动进程,将日志输出到log.txt文件中方便调试:
[root@lingg src]# nohup java -jar demo-0.0.1-SNAPSHOT.jar >log.txt &
[1] 27019
[root@lingg src]# nohup: 忽略输入重定向错误到标准输出端
^C
[root@lingg src]# ps -ef | grep 27019
root 27019 26409 29 22:26 pts/0 00:00:07 java -jar demo-0.0.1-SNAPSHOT.jar
root 27082 26409 0 22:26 pts/0 00:00:00 grep --color=auto 27019
url:http://域名:端口号/upload
form-data:
file:选择本地文件

返回结果:
{
"result": "success",
"path": "/usr/local/src/abca08b5-f6f6-4077-95ac-ae91d5cb76a7.jpeg"
}
查看目录下对应的文件:

文件成功上传至本地:上传成功。
第三步:使用微信小程序进行测试:


返回结果:
{errMsg: "chooseImage:ok", tempFilePaths: Array(1), tempFiles: Array(1)}
errMsg: "chooseImage:ok"
tempFilePaths: Array(1)
0: "http://tmp/F5tqcfC9HecR4b038c8febd34d7dd2bf9fd34b09561f.jpg"
length: 1
nv_length: (...)
__proto__: Array(0)
tempFiles: Array(1)
0: {path: "http://tmp/F5tqcfC9HecR4b038c8febd34d7dd2bf9fd34b09561f.jpg", size: 30935}
length: 1
nv_length: (...)
__proto__: Array(0)
__proto__: Object
{statusCode: 400, data: "{"timestamp":"2021-09-17T16:21:00.571+00:00","status":400,"error":"Bad Request","path":"/upload"}", header: {…}, cookies: Array(0), errMsg: "uploadFile:ok"}
cookies: Array(0)
length: 0
nv_length: (...)
__proto__: Array(0)
data: "{"timestamp":"2021-09-17T16:21:00.571+00:00","status":400,"error":"Bad Request","path":"/upload"}"
errMsg: "uploadFile:ok"
header:
Connection: "close"
Content-Type: "application/json"
Date: "Fri, 17 Sep 2021 16:21:00 GMT"
Transfer-Encoding: "chunked"
__proto__: Object
statusCode: 400
__proto__: Object

可以看到,HttpCode是400 BadRequest
而且在springboot程序上打上断点完全没有反应。
目前还没有找出什么原因,网上找了一下说是请求url太长导致的,个人觉得也可能是因为小程序发送的请求参数和Controller的参数类型不一致导致的。
先把坑留在这里,明天有空再慢慢排查!希望有懂的大神能指点一二!万分感谢!
更新:
【已解决】
由于昨天晚上给自己留了坑,所以起了个大早起来填坑!
首先考虑是不是参数的格式不对,因为我查了一下wx.uploadFile()的参数是文件的临时存放地址组成的数组,而uploadController接口中的参数是spring独有的multipartFile,于是接口的参数除了MultipartFile类型,还加上了HttpServletRequest和HttpServletResponse,妄图从中以取参数的方式拿到对应的文件。
@RestController
public class UpLoadController {
@RequestMapping("/upload")
public Map<String,String> upload(HttpServletRequest request, HttpServletResponse response,@RequestParam("file") MultipartFile file ){
Map<String,String> resultMap = new HashMap<>();
String filePath = request.getParam("filePath");
System.out.println("filePath");
return resultMap;
}
}
结果发现根本没有输出任何东西,也许请求根本没有打到这个接口上来
然后考虑是不是参数不对应?于是我直接去掉了原来的MultipartFile参数,换成了HttpServletRequest和HttpServletResponse,然后输出,发现输出了null!最起码说明能接受到请求了!
那么打上断点Debug一下,看看请求里究竟有什么!
一层一层剥开后发现:请求中居然有这张图片,只不过被一层层封装,并且被我们自己起了一个别的名字而我们自己却不知道!
从图中可以看出,接受到的HttpServletRequest中居然有这个文件,只不过是被封装在一个键为“123”的数组中,这个键名其实就是我们在wx.uploadFiles()请求中参数name的值!
不得不说是自己坑了自己!我们我们只需要在接口的参数前加上注解@RequestParam(“123”)即可!
@RestController
public class UpLoadController {
@RequestMapping("/upload")
public Map<String,String> upload(HttpServletRequest request, HttpServletResponse response,@RequestParam("123") MultipartFile file ){
Map<String,String> resultMap = new HashMap<>();
String path = "/Users/liushanlin/Desktop/";
String fileName = file.getOriginalFilename();
String suffixName = fileName.substring(fileName.indexOf("."));
fileName = UUID.randomUUID()+suffixName;
System.out.println("fileName"+fileName);
System.out.println("fileType:"+suffixName);
File targetFile = new File(path);
if(!targetFile.exists()){
targetFile.mkdir();
}
File saveFile = new File(targetFile,fileName);
try{
file.transferTo(saveFile);
System.out.println("上传成功");
String path1 = path+fileName;
System.out.println(path1);
resultMap.put("result","success");
resultMap.put("path",path1);
} catch (IOException e) {
e.printStackTrace();
System.out.println("执行失败");
resultMap.put("result","failed");
resultMap.put("path","null");
}
System.out.println(file);
return resultMap;
}
}
哥德巴林猜想:
wx.uploadFile()发送的http请求中将name的值作为参数的名称,文件数组作为参数的值。而name的值又是我们自己去设定的,所以每次取文件的时候,只需要将参数的名称指定为我们在wx.uploadFile( )中设定好的name的值即可成功接收文件!
后来可以看到这一点在微信小程序开发文档中已经讲的很清楚了,猜想正确,至此完美结束。
附:
wx.chooseImage(Object object)
从本地相册选择图片或使用相机拍照。
参数
Object object
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
count | number | 9 | 否 | 最多可以选择的图片张数 |
sizeType | Array. | [‘original’, ‘compressed’] | 否 | 所选的图片的尺寸 |
sourceType | Array. | [‘album’, ‘camera’] | 否 | 选择图片的来源 |
success | function | 否 | 接口调用成功的回调函数 | |
fail | function | 否 | 接口调用失败的回调函数 | |
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.sizeType 的合法值
值 | 说明 | 最低版本 |
---|---|---|
original | 原图 | |
compressed | 压缩图 |
object.sourceType 的合法值
值 | 说明 | 最低版本 |
---|---|---|
album | 从相册选图 | |
camera | 使用相机 |
object.success 回调函数
参数
Object res
属性 | 类型 | 说明 | 最低版本 |
---|---|---|---|
tempFilePaths | Array. | 图片的本地临时文件路径列表 (本地路径) | |
tempFiles | Array. | 图片的本地临时文件列表 | 1.2.0 |
res.tempFiles 的结构
属性 | 类型 | 说明 |
---|---|---|
path | string | 本地临时文件路径 (本地路径) |
size | number | 本地临时文件大小,单位 B |
Wx.uploadFile(Object object)
将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中 content-type
为 multipart/form-data
。
参数
Object object
属性 | 类型 | 默认值 | 必填 | 说明 | 最低版本 |
---|---|---|---|---|---|
url | string | 是 | 开发者服务器地址 | ||
filePath | string | 是 | 要上传文件资源的路径 (本地路径) | ||
name | string | 是 | 文件对应的 key,开发者在服务端可以通过这个 key 获取文件的二进制内容 | ||
header | Object | 否 | HTTP 请求 Header,Header 中不能设置 Referer | ||
formData | Object | 否 | HTTP 请求中其他额外的 form data | ||
timeout | number | 否 | 超时时间,单位为毫秒 | 2.10.0 | |
success | function | 否 | 接口调用成功的回调函数 | ||
fail | function | 否 | 接口调用失败的回调函数 | ||
complete | function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
object.success 回调函数
参数
Object res
属性 | 类型 | 说明 |
---|---|---|
data | string | 开发者服务器返回的数据 |
statusCode | number | 开发者服务器返回的 HTTP 状态码 |
欢迎批评指正!