微信小程序上传图片至服务器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;@RestControllerpublic 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=10MBspring.servlet.multipart.max-request-size=100MB
第一步在本地进行测试,使用Postman进行测试:
url:http://localhost/uploadform-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 27019root27019 26409 29 22:26 pts/0 00:00:07 java -jar demo-0.0.1-SNAPSHOT.jarroot27082 26409 0 22:26 pts/0 00:00:00 grep --color=auto 27019
url:http://域名:端口号/uploadform-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: 1nv_length: (...)__proto__: Array(0)tempFiles: Array(1)0: {path: "http://tmp/F5tqcfC9HecR4b038c8febd34d7dd2bf9fd34b09561f.jpg", size: 30935}length: 1nv_length: (...)__proto__: Array(0)__proto__: Object
{statusCode: 400, data: "{"timestamp":"-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: 0nv_length: (...)__proto__: Array(0)data: "{"timestamp":"-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 16:21:00 GMT"Transfer-Encoding: "chunked"__proto__: ObjectstatusCode: 400__proto__: Object
可以看到,HttpCode是400 BadRequest
而且在springboot程序上打上断点完全没有反应。
目前还没有找出什么原因,网上找了一下说是请求url太长导致的,个人觉得也可能是因为小程序发送的请求参数和Controller的参数类型不一致导致的。
先把坑留在这里,明天有空再慢慢排查!希望有懂的大神能指点一二!万分感谢!
更新:
【已解决】
由于昨天晚上给自己留了坑,所以起了个大早起来填坑!
首先考虑是不是参数的格式不对,因为我查了一下wx.uploadFile()的参数是文件的临时存放地址组成的数组,而uploadController接口中的参数是spring独有的multipartFile,于是接口的参数除了MultipartFile类型,还加上了HttpServletRequest和HttpServletResponse,妄图从中以取参数的方式拿到对应的文件。
@RestControllerpublic 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”)即可!
@RestControllerpublic 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
object.sizeType 的合法值
object.sourceType 的合法值
object.success 回调函数
参数
Object res
res.tempFiles 的结构
Wx.uploadFile(Object object)
将本地资源上传到服务器。客户端发起一个 HTTPS POST 请求,其中content-type
为multipart/form-data
。
参数
Object object
object.success 回调函数
参数
Object res
欢迎批评指正!