今天接到命令要求在微信小程序中的专家问答模块里,添加一个在提问时可以上传附件的功能(doc.xls.ppt.pdf).
首先梳理一下流程:
1.用户点击“上传”按钮选择附件后,将附件首先上传到临时文件夹下,我选在放在tomcat编译后的文件夹中。
2.当用户完善提问内容,点击“发布问题”之后,将附件从临时文件夹中转存到正式的资源库中。
3.其他用户点开问题后,通过“打开附件”按钮下载浏览附件。
因为我是萌新,而且阅读我随笔很多也是萌新,所以在这里首先提一下困扰了我很久的在服务器环境中文件存储过程中相对、绝对路径,以及最关键的数据库存储路径的问题,以下:)
1.首先在File对象构造函数中,提供的文件地址必须是绝对路径或url地址,不能使用使用相对路径,因此,不管是正式资源库,还是临时文件库,我们都要获取绝对路径;
-正式资源库好解决,因为是自己创建的文件夹,可以直接使用类似,"C://expertFile/"+文件名的方式创建File对象。
-临时文件夹我们可以使用request对象获取session对象,然后获取tomcat编译文件的根目录,request.getSession().getServletContext().getRealPath("expertFile")+文件名的方式创建File对象
2.好,这是存储过程中径路的解决办法,但是这些都是本地路径,数据库中不可能存本地路径,因为到了服务器环境下,让用户去本地去找附件肯定找不到,所以在数据库中,我们采用URL
路径存储,URL路径不止可以访问项目的根目录,还可以进行自定义配置。如下
其中Document base是你服务器的正式文件资源库的地址,Path是你的URL地址。
然后用户就可以通过这样的URL地址访问并下载正式文件库中的附件了。所以数据库中存储的是URL地址
这里需要注意一下在存储的时候IP中一定不要存localhost要存服务器的IP地址。
路径问题说明白之后,我开始正题,微信小程序开发
这里,我又遇到了一个问题,在微信小程序中,为了用户的安全考虑,微信没有提供让用户选择本地文档接口的API,但是翻找API的过程中,我发现了一个接口
“wx.chooseMessageFile”,这个接口允许用户在自己的聊天记录中选择文档进行上传,于是我就想先把功能实现,选择了这个接口。但是这个接口的作用仅仅是
将用户选择的文档上传到微信提供的一个临时路径中,你还需要把他下载到本地的临时文件夹中,这个接口会返回一个上面说过的URL地址,接着我们使用
"wx.uploadFile"接口将请求传递到后台,进行处理,
下面贴一下微信小程序端的基本代码,至于文件大小,格式校验啥的,各位根据自己需求添加修改
wx.chooseMessageFile({
count:1, //上传的文件数目
type:'file', //上传类型,一共三种,可以去微信小程序API看
success(res){
var tempFilePaths = res.tempFiles[0]; //tempFiles对象中,对返回你上传文件基本信息,name文件名,size文件大小,单位是B,path微信提供的临时存放路径,我们需要这个
that.setData({
fileName : tempFilePaths.name,
})
wx.uploadFile({
url: serverUrl +'/upload_uploadExpert.action', //将上传请求发到后台处理
filePath: res.tempFiles[0].path,
name: 'file', //这个属性比较重要,这个属性值与spring中的全局变量名一致,spring会自动装配,将附件信息存到后台的file对象中。非常方便。
formData:{
fileData: res.tempFiles[0].name,
},
header: {
"Content-Type": "multipart/form-data"
},
success:function(res){
var json = JSON.parse(res.data);
console.log(json);
that.setData({
fileName: json.fileName,
filepath: json.filepath,
})
}
})
}
})
接下来是后台代码,其实路径问题弄明白,我觉得就没什么难点了
String path = request.getSession().getServletContext().getRealPath("expertFile"); //这里最好在做一下文件夹是否存在的判断,我这里博客中就去掉了
String temporaryFilePath = file.getPath();
//首先根据微信小程序返回的临时地址,从微信提供的URL地址读取文件,这个file对象就是自动装配的File类型的file对象
File temporaryFile = new File(temporaryFilePath);
if(temporaryFile.exists()){
BufferedInputStream is = new BufferedInputStream(new FileInputStream(temporaryFile));
ByteArrayOutputStream io = new ByteArrayOutputStream((int)file.length());
int buf_size = 4194304; //这里我限制了上传附件最大为4M
byte[] bytes = new byte[buf_size];
int len = 0;
while(-1 != (len = is.read(bytes,0,buf_size))){
io.write(bytes,0,len);
}}
//拿到文件的byte之后,下面的代码是存储到临时文件夹中
String filepath = path+文件名;
File file2 = new File(filepath);
FileOutputStream stream = new FileOutputStream(file2);
BufferedOutputStream bo = new BufferedOutputStream(stream);
bo.write(io.toByteArray());
//记得关闭连接
is.close();
io.close();
stream.close();
bo.close();
好了现在,用户上传的附件已经存储到了本地临时文件夹,至于临时文件夹到正式文件资源库的过程,和转存临时文件的过程一样,就不再赘述,关键点也都说了,就是数据库的存储地址。
现在说最后一步,用户打开浏览附件
这一步更加简单,没有后台操作:
微信的API提供了两个接口“wx.downloadFile”和“wx.openDocument”分别负责下载和打开文档,你只需要从后台数据库查找出URL地址就可以了。
wx.downloadFile({
url: filepath, //这就是你从数据库查找出的URL地址
success: function (res) {
var tempFilePath = res.tempFilePath; //微信接口下载文档后返回的URL地址,打开文档需要用到这个
console.log(tempFilePath);
var suffixs = bufName[1]; //文件后缀
that.openDocument2(tempFilePath, suffixs);
}
})
openDocument2:function(tempFilePath, suffixs){
wx.openDocument({
filePath: tempFilePath,
fileType: suffixs, //打开文件类型
success: function (res) {
console.log('附件打开成功');
},
fail: function (res) {
console.log('失败了');
}
})
},
这里需要注意的一点是,在openDocument接口中,有个fileType值,这个值是说打开的文件的类型,也就说若这个值的是doc文件,那么就只能正常打开“XXX.doc"文件,打开其他的文件
就会乱码,所有最好把第二个方法封装一下,不然再分别做判断代码就是垃圾代码了,至于都支持什么格式的文件,可以上微信API网站查一下。