四川建设网官方网站,wordpress 页眉,高级网页设计师,广州工程承包总公司前言
之前的文章有写过 vuespringboot使用文件流实现文件下载 实现如何通过
D:\file\文件名.文件格式的形式进行下载文件
但是它对于很多业务场景相对适用性不是很广泛。 以及 elementUI加springboot实现上传excel文件给后端并读取excel 也只能是通过elementui的元素类型进行…前言
之前的文章有写过 vuespringboot使用文件流实现文件下载 实现如何通过
D:\file\文件名.文件格式的形式进行下载文件
但是它对于很多业务场景相对适用性不是很广泛。 以及 elementUI加springboot实现上传excel文件给后端并读取excel 也只能是通过elementui的元素类型进行上传。
因此本次文章将通过两种方式 存放本地文件和存放字节流两种方式教大家如何进行文件的上传和下载适用绝大部分场景.
存放本地文件实现上传和下载
我们在开发完项目并且将项目部署到服务器的时候如果我们有实现上传的功能实际上还是保存文件在部署项目的这个服务器上下载也是从服务器下载因此我们就可以直接使用存放本地文件的方式实现上传和下载
存放本地文件-上传
我们都知道在前端如果需要接收文件的传递给后端的话可以使用 formData进行保存数据,那么对应前端代码如下:
前端
为演示方便后续上传都使用原生的input进行获取文件 界面
input typefile idupload /
button onclickuploadFile上传/buttonjs逻辑
uploadFile() {// 获取上传图片let dom document.getElementById(upload);// 定义接收文件的formData,并用file去接收数据let formDataInfo new FormData();// 接收第一个文件适用单文件formDataInfo.append(file,dom.files[0]);// 需要引入axiosthis.$axios({method: post, // 为post请求url: /fileUplod// 请求后端的路径改成自己的就行,data: formDataInfo,// 传递参数responseType: json,// 响应类型}).then(res {// 响应数据})以上是适用于单文件如果需要上传多文件参考如下代码
uploadFile() {// 获取上传图片let dom document.getElementById(upload);// 定义接收文件的formData,并用file去接收数据let formDataInfo new FormData();// 接收文件数量formDataInfo.append(length,dom.files.length)// 遍历文件加入formData,后端处理的时候获取length的长度进行遍历文件for (let i 0;idom.files.length;i) {formDataInfo.append(filei,dom.files[i]);}// 需要引入axiosthis.$axios({method: post, // 为post请求url: /fileUplod// 请求后端的路径改成自己的就行,data: formDataInfo,// 传递参数responseType: json, // 响应类型}).then(res {// 响应数据})
}后端 POSTPath(fileUplod)public String fileUplod(FormDataMultiPart form) {try {// 需要保存文件路径String path D:/file;// 文件流InputStream inputStream form.getField(file).getValueAs(InputStream.class);// 文件名String fileName form.getField(file).getContentDisposition().getFileName();// 调用下面的保存本地文件方法uploadFileToLocal(inputStream,path,fileName);return 上传文件成功!;}catch(Exception e) {return 上传文件到本地磁盘失败 e.getMessage();}}/*** param inputStream 文件流* param path 上传路径* param fileName 文件名* return 如果返回含义字符串【报错】上传失败,否则返回文件路径* author ks027276* description 上传文件到本地方法*/public String uploadFileToLocal(InputStream inputStream, String path, String fileName) throws Exception {try {File folder new File(path);// 创建没有的文件夹if (!folder.isDirectory()) {folder.mkdirs();}//创建空文件FileOutputStream outputStream new FileOutputStream(path / fileName);// 将文件流数据填充到空文件int index 0;byte[] bytes new byte[1024];while ((index inputStream.read(bytes)) ! -1) {outputStream.write(bytes, 0, index);outputStream.flush();}inputStream.close();outputStream.close();return path / fileName;} catch (Exception e) {return 【报错】 e.getMessage();}}假如需要获取文件名使用代码:
String fileName form.getField(file).getContentDisposition().getFileName();值得一提的是如果上传文件名为中文那么这个方式上传会乱码需要处理为如下:
String fileName new String(form.getField(file).getContentDisposition().getFileName()
.getBytes(iso-8859-1), UTF-8);上述皆为单文件上传的方式假如使用我上方前端多文件上传逻辑其实差不多就是多了一个遍历而已具体逻辑如下: POSTPath(fileUplod)public String fileUplod(FormDataMultiPart form) {try {// 需要保存文件路径String path D:/file;for (int i 0;i Integer.valueof(form.getField(length).getvalue());i) {// 文件流InputStream inputStream form.getField(filei).getValueAs(InputStream.class);// 文件名String fileName form.getField(filei).getContentDisposition().getFileName();// 调用下面的保存本地文件方法uploadFileToLocal(inputStream,path,fileName);}return 上传文件成功!;}catch(Exception e) {return 上传文件到本地磁盘失败 e.getMessage();}
}/*** param inputStream 文件流* param path 上传路径* param fileName 文件名* return 如果返回含义字符串【报错】上传失败,否则返回文件路径* author ks027276* description 上传文件到本地方法*/public String uploadFileToLocal(InputStream inputStream, String path, String fileName) throws Exception {try {File folder new File(path);// 创建没有的文件夹if (!folder.isDirectory()) {folder.mkdirs();}//创建空文件FileOutputStream outputStream new FileOutputStream(path / fileName);// 将文件流数据填充到空文件int index 0;byte[] bytes new byte[1024];while ((index inputStream.read(bytes)) ! -1) {outputStream.write(bytes, 0, index);outputStream.flush();}inputStream.close();outputStream.close();return path / fileName;} catch (Exception e) {return 【报错】 e.getMessage();}}保存结果
以下截图为我用上方功能实现保存到本地:
存放本地文件-下载
下载的话既然上面已经接收到了路径那么直接用路径去查找就好了 路径形式如下:
D:/file/1.jpg前端代码
button onclickgetFile获取文件/button// path值形式为:D:/file/1.jpg
// name值形式为:1.jpg
getFile(path,name) {// 需要引入axiosthis.axios({method: get, // 为get请求url: /downFile// 请求后端的路径改成自己的就行,data: {path: path,name: name},// 传递参数responseType: json,// 响应类型}).then(res {var a document.createElement(a);a.href res.data // 这里需要根据自己实际项目作变更可能你的数据在res,或res.data或res.data.datadocument.body.appendChild(a);a.click();document.body.removeChild(a);})}后端 /*** 文件下载 根据路径*/
// response类型引用为:
import javax.ws.rs.core.Response;GETPath(/downFile)public Response downLoadPanorama(QueryParam(path) String path,QueryParam(name) String name) {try {FileInputStream inputStream new FileInputStream(path);byte[] bytes toByteArray(inputStream);return Response.ok(new StreamingOutput() {Overridepublic void write(OutputStream output) throws IOException, WebApplicationException {try {output.write(bytes);} catch (Exception ex) {}}}).header(Content-disposition,attachment;filename name).header(Cache-Control, no-cache).build();} catch (Exception e) {e.printStackTrace();return Response.status(Response.Status.NOT_FOUND).build();}}使用上面的代码会将文件下载下来 形式如:
存放字节流的形式上传和下载
一般来说会更推荐使用字节流的方式进行实现文件的上传和下载因为是文件流所以我们可以更方便便捷的用它实现各种操作。 存字节流实际上是保存在数据库因此对数据库的内存会占用更多。
存放字节流-上传
首先数据库表的字段需要新建blob类型的字段接收数据 在java代码对象需要用byte数组类型接收文件转字节流的字段属性接收
Data
public class FileObject {private byte[] file;
}前端
界面
input typefile idupload /
button onclickuploadFile上传/buttonjs逻辑
uploadFile() {// 获取上传图片let dom document.getElementById(upload);// 定义接收文件的formData,并用file去接收数据let formDataInfo new FormData();// 接收第一个文件适用单文件formDataInfo.append(file,dom.files[0]);// 需要引入axiosthis.$axios({method: post, // 为post请求url: /fileUplod// 请求后端的路径改成自己的就行,data: formDataInfo,// 传递参数responseType: json,// 响应类型}).then(res {// 响应数据})以上是适用于单文件如果需要上传多文件参考如下代码
uploadFile() {// 获取上传图片let dom document.getElementById(upload);// 定义接收文件的formData,并用file去接收数据let formDataInfo new FormData();// 接收文件数量formDataInfo.append(length,dom.files.length)// 遍历文件加入formData,后端处理的时候获取length的长度进行遍历文件for (let i 0;idom.files.length;i) {formDataInfo.append(filei,dom.files[i]);}// 需要引入axiosthis.$axios({method: post, // 为post请求url: /fileUplod// 请求后端的路径改成自己的就行,data: formDataInfo,// 传递参数responseType: json, // 响应类型}).then(res {// 响应数据})
}其实逻辑是一样的和存放本地文件上传的数据一样 最主要的逻辑差距在后端
后端 POSTPath(fileUplod)public String fileUplod(FormDataMultiPart form) {try {// 文件流InputStream inputStream form.getField(file).getValueAs(InputStream.class);// 调用下面的保存本地文件方法byte[] fileBytes getBytes(inputStream);// 调用新增数据库sql存到数据库// 这边就属于自己的功能逻辑了我以下就不写了return 上传文件成功!;}catch(Exception e) {return 上传文件到数据库失败 e.getMessage();}
}/*** 存字节流到数据库* param inputStream 字节流* 有值说明获取成功无值说明失败*/public byte[] getBytes(InputStream inputStream) throws Exception {try {BufferedInputStream bufferedInputStream new BufferedInputStream(inputStream);ByteArrayOutputStream byteArrayOutputStream new ByteArrayOutputStream();byte[] buffer;int len;byte[] buf new byte[2048];while ((len bufferedInputStream.read(buf)) ! -1) {byteArrayOutputStream.write(buf, 0, len);}byteArrayOutputStream.flush();buffer byteArrayOutputStream.toByteArray();inputStream.close();return buffer;} catch (Exception e) {return null;}}
上述皆为单文件上传的方式假如使用我上方前端多文件上传逻辑其实差不多就是多了一个遍历而已具体逻辑如下: POSTPath(fileUplod)public String fileUplod(FormDataMultiPart form) {try {for (int i 0;i Integer.valueof(form.getField(length).getvalue());i) {// 文件流InputStream inputStream form.getField(filei).getValueAs(InputStream.class);// 调用下面的保存本地文件方法byte[] filei getBytes(inputStream);// 调用新增数据库sql存到数据库// 这边就属于自己的功能逻辑了我以下就不写了}return 上传文件成功!;}catch(Exception e) {return 上传文件到数据库失败 e.getMessage();}
}/*** 存字节流到数据库* param inputStream 字节流* 有值说明获取成功无值说明失败*/public byte[] getBytes(InputStream inputStream) throws Exception {try {BufferedInputStream bufferedInputStream new BufferedInputStream(inputStream);ByteArrayOutputStream byteArrayOutputStream new ByteArrayOutputStream();byte[] buffer;int len;byte[] buf new byte[2048];while ((len bufferedInputStream.read(buf)) ! -1) {byteArrayOutputStream.write(buf, 0, len);}byteArrayOutputStream.flush();buffer byteArrayOutputStream.toByteArray();inputStream.close();return buffer;} catch (Exception e) {return null;}}如果需要获取文件名参照上面存放本地文件方式有说明
存到数据库结果为: 是一个BLOB数据
存放字节流-下载
通过sql查询语句我们查找到存放的字节流文件数据展示到前端结果为: 是一个Array数组的形式
后端逻辑就不写了单纯就是一个sql查数据而已
如果是图片文件可以使用一个img元素直接展示图片
img :srcbase64/
button onclickshowImage上传/button上面我们绑定了一个自定义属性:base64js逻辑直接把它拿过来赋值即可
showImage(byte,type) {let binary ;const bytes new Uint8Array(byte);const len bytes.byteLength;for (let i 0; i len; i) {binary String.fromCharCode(bytes[i]);}// base64前缀let base64Before ;if (type jpg || type jpeg) {base64Before data:image/jpeg;base64,;} else if (type png) {base64Before data:image/png;base64,;}this.base64 base64Before window.btoa(binary);
}假如你需要拿到字节流下载文件的话使用如下逻辑:
// byte字节流数据形式如: [11,-1,44,20,......]
// _type,数据形式如: jpg txt
// name,文件名数据形式如 1.jpg 2.txt
downFile (byte,_type,name) {var eleLink document.createElement(a);// 根据文件类型设定blob文件类型let fileType this.extToMimes(_type);// 设定下载文件名eleLink.download name;// 设置a标签不显示eleLink.style.display none;// 将文件流转Uint8Arrayconst bytes new Uint8Array(byte);// 将转换后的数据和获取的文件类型创建blobvar blob new Blob([bytes],{type: fileType});eleLink.href URL.createObjectURL(blob);// 自动触发点击document.body.appendChild(eleLink);eleLink.click();// 然后移除document.body.removeChild(eleLink);
}
// 根据传入的类型设定blob文件类型extToMimes(ext) {let type undefined;switch (ext) {case jpg:type image/jpegcase png:type image/pngcase jpeg:type image/jpegbreak;case txt:type text/plainbreak;case xls:type application/vnd.ms-excelbreak;case doc:type application/mswordbreak;case xlsx:type application/vnd.ms-excelbreak;default:}return type;}下载结果
通过以上可以下载文件并且正确显示出内容 测试有效
结语
以上为通过字节流和本地文件的方式进行上传和下载的方法。