SpringBoot+ElementUI实现通用文件下载请求(全流程图文详细教程)
場(chǎng)景
在某些場(chǎng)景下需要前端瀏覽器從服務(wù)器端下載文件,比如需要下載導(dǎo)入Excel的模板。
?
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
關(guān)注公眾號(hào)
霸道的程序猿
獲取編程相關(guān)電子書、教程推送與免費(fèi)下載。
實(shí)現(xiàn)
既然是實(shí)現(xiàn)通用下載接口,就要實(shí)現(xiàn)在后端配置一個(gè)下載文件的路徑,在前端進(jìn)行下載請(qǐng)求時(shí)傳遞要下載的文件的名字,然后請(qǐng)求公共接口進(jìn)行下載。
首先是在前端使用ElementUI的el-link添加一個(gè)下載鏈接
????????? <el-linktype="info"style="font-size:12px"@click="downloadTemplate('lxszTemplate.xlsx')">下載模板</el-link>這里設(shè)置了其點(diǎn)擊事件是調(diào)用downloadTemplate方法并傳遞一個(gè)文件名參數(shù),這個(gè)文件名就是要下載的文件名。
然后在對(duì)應(yīng)的點(diǎn)擊事件中
??? downloadTemplate(value) {download(value).then((response) => {}).catch((error) => {alert("錯(cuò)誤:" + error);});},這里執(zhí)行了一個(gè)download方法并傳遞文件名參數(shù)。
這個(gè)download方法是引用的第三方j(luò)s中作為公共方法的。
引入方式
import { download } from "@/utils/badao";在utils下的badao.js中
// 通用下載方法 export function download(fileName) {window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + false; }將此方法進(jìn)行暴露,作為公共方法。
在通用下載方法中使頁(yè)面跳轉(zhuǎn)window.location.href ,對(duì)應(yīng)的url是SpringBoot中后臺(tái)的接口。
這里的baseURL是在badao.js中聲明的常量
const baseURL = process.env.VUE_APP_BASE_API對(duì)此常量的賦值是取得全局變量process的屬性,它對(duì)應(yīng)的是在vue.config.js中配置的代理的地址
??? proxy: {[process.env.VUE_APP_BASE_API]: {target: `http://localhost:8080`,changeOrigin: true,pathRewrite: {['^' + process.env.VUE_APP_BASE_API]: ''}}},這里是我本地的8080端口。
然后在上面的通用的下載方法中在URL中還拼接了兩個(gè)參數(shù)
一個(gè)是文件名參數(shù),調(diào)用的js的encodeURI方法可以將字符串作為URL進(jìn)行編碼,一個(gè)是是否刪除的參數(shù),默認(rèn)是false,作為下載成功后是否將文件給刪除,即實(shí)現(xiàn)單次下載還是多次下載。
然后在這個(gè)url對(duì)應(yīng)SprinBoot后臺(tái)接口方法中
??? @GetMapping("common/download")public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) {try {if (!FileUtils.isValidFilename(fileName)) {throw new Exception(StringUtils.format("文件名稱({})非法,不允許下載。 ", fileName));}String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);String filePath = RuoYiConfig.getDownloadPath() + fileName;response.setCharacterEncoding("utf-8");response.setContentType("multipart/form-data");response.setHeader("Content-Disposition","attachment;fileName=" + FileUtils.setFileDownloadHeader(request, realFileName));FileUtils.writeBytes(filePath, response.getOutputStream());if (delete) {FileUtils.deleteFile(filePath);}} catch (Exception e) {log.error("下載文件失敗", e);}}首先調(diào)用了文件處理工具類的驗(yàn)證方法,驗(yàn)證文件名稱是否合法。
這里是設(shè)置了指定文件名稱格式。
方法實(shí)現(xiàn)
??? public static boolean isValidFilename(String filename){return filename.matches(FILENAME_PATTERN);}其中參數(shù)為常量
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";下面是對(duì)服務(wù)器上文件路徑的獲取
String filePath = RuoYiConfig.getDownloadPath() + fileName;其中RuoyiConfig是配置類,用來(lái)讀取項(xiàng)目相關(guān)配置,即配置在application.yml中的內(nèi)容。
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component;/*** 讀取項(xiàng)目相關(guān)配置** @author ruoyi*/ @Component @ConfigurationProperties(prefix = "ruoyi") public class RuoYiConfig {/** 項(xiàng)目名稱 */private String name;/** 版本 */private String version;/** 版權(quán)年份 */private String copyrightYear;/** 實(shí)例演示開關(guān) */private boolean demoEnabled;/** 上傳路徑 */private static String profile;/** 獲取地址開關(guān) */private static boolean addressEnabled;public String getName(){return name;}public void setName(String name){this.name = name;}public String getVersion(){return version;}public void setVersion(String version){this.version = version;}public String getCopyrightYear(){return copyrightYear;}public void setCopyrightYear(String copyrightYear){this.copyrightYear = copyrightYear;}public boolean isDemoEnabled(){return demoEnabled;}public void setDemoEnabled(boolean demoEnabled){this.demoEnabled = demoEnabled;}public static String getProfile(){return profile;}public void setProfile(String profile){RuoYiConfig.profile = profile;}public static boolean isAddressEnabled(){return addressEnabled;}public void setAddressEnabled(boolean addressEnabled){RuoYiConfig.addressEnabled = addressEnabled;}/*** 獲取頭像上傳路徑*/public static String getAvatarPath(){return getProfile() + "/avatar";}/*** 獲取下載路徑*/public static String getDownloadPath(){return getProfile() + "/download/";}/*** 獲取上傳路徑*/public static String getUploadPath(){return getProfile() + "/upload";} }這里的getDownloadPath就是獲取設(shè)置的下載路徑的方法,方法具體實(shí)現(xiàn)
??? public static String getDownloadPath(){return getProfile() + "/download/";}就是返回profile這個(gè)節(jié)點(diǎn)
??? public static String getProfile(){return profile;}因?yàn)槭褂昧?#64;ConfigurationProperties(prefix = "ruoyi")
所以在對(duì)應(yīng)的application.yml中獲取profile就是獲取ruoyi下的profile的值
?
這里配置的路徑加上/download/再加上一個(gè)文件名就是服務(wù)器上要下載的模板文件的位置。
所以要提前將此文件放置在服務(wù)器上對(duì)應(yīng)的位置。
這里服務(wù)器是我本地
?
然后對(duì)文件名進(jìn)行一個(gè)添加時(shí)間戳的操作,防止多次下載重名問(wèn)題。
然后設(shè)置響應(yīng)編碼、響應(yīng)頭、響應(yīng)類型。
然后調(diào)用了文件工具類的輸出文件到Byte數(shù)組的方法writeBytes
方法實(shí)現(xiàn)
??? /*** 輸出指定文件的byte數(shù)組** @param filePath 文件路徑* @param os 輸出流* @return*/public static void writeBytes(String filePath, OutputStream os) throws IOException{FileInputStream fis = null;try{File file = new File(filePath);if (!file.exists()){throw new FileNotFoundException(filePath);}fis = new FileInputStream(file);byte[] b = new byte[1024];int length;while ((length = fis.read(b)) > 0){os.write(b, 0, length);}}catch (IOException e){throw e;}finally{if (os != null){try{os.close();}catch (IOException e1){e1.printStackTrace();}}if (fis != null){try{fis.close();}catch (IOException e1){e1.printStackTrace();}}}}以及下載文件名重新編碼的方法setFileDownloadHeader
方法實(shí)現(xiàn)
?
?? /*** 下載文件名重新編碼** @param request 請(qǐng)求對(duì)象* @param fileName 文件名* @return 編碼后的文件名*/public static String setFileDownloadHeader(HttpServletRequest request, String fileName)throws UnsupportedEncodingException{final String agent = request.getHeader("USER-AGENT");String filename = fileName;if (agent.contains("MSIE")){// IE瀏覽器filename = URLEncoder.encode(filename, "utf-8");filename = filename.replace("+", " ");}else if (agent.contains("Firefox")){// 火狐瀏覽器filename = new String(fileName.getBytes(), "ISO8859-1");}else if (agent.contains("Chrome")){// google瀏覽器filename = URLEncoder.encode(filename, "utf-8");}else{// 其它瀏覽器filename = URLEncoder.encode(filename, "utf-8");}return filename;}然后根據(jù)傳遞的參數(shù)是否刪除模板文件,執(zhí)行刪除的工具類方法deleteFile
方法實(shí)現(xiàn)
??? /*** 刪除文件** @param filePath 文件* @return*/public static boolean deleteFile(String filePath){boolean flag = false;File file = new File(filePath);// 路徑為文件且不為空則進(jìn)行刪除if (file.isFile() && file.exists()){file.delete();flag = true;}return flag;}完整的文件操作工具類代碼
package com.ruoyi.common.utils.file;import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.http.HttpServletRequest;/*** 文件處理工具類** @author ruoyi*/ public class FileUtils {public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";/*** 輸出指定文件的byte數(shù)組** @param filePath 文件路徑* @param os 輸出流* @return*/public static void writeBytes(String filePath, OutputStream os) throws IOException{FileInputStream fis = null;try{File file = new File(filePath);if (!file.exists()){throw new FileNotFoundException(filePath);}fis = new FileInputStream(file);byte[] b = new byte[1024];int length;while ((length = fis.read(b)) > 0){os.write(b, 0, length);}}catch (IOException e){throw e;}finally{if (os != null){try{os.close();}catch (IOException e1){e1.printStackTrace();}}if (fis != null){try{fis.close();}catch (IOException e1){e1.printStackTrace();}}}}/*** 刪除文件** @param filePath 文件* @return*/public static boolean deleteFile(String filePath){boolean flag = false;File file = new File(filePath);// 路徑為文件且不為空則進(jìn)行刪除if (file.isFile() && file.exists()){file.delete();flag = true;}return flag;}/*** 文件名稱驗(yàn)證** @param filename 文件名稱* @return true 正常 false 非法*/public static boolean isValidFilename(String filename){return filename.matches(FILENAME_PATTERN);}/*** 下載文件名重新編碼** @param request 請(qǐng)求對(duì)象* @param fileName 文件名* @return 編碼后的文件名*/public static String setFileDownloadHeader(HttpServletRequest request, String fileName)throws UnsupportedEncodingException{final String agent = request.getHeader("USER-AGENT");String filename = fileName;if (agent.contains("MSIE")){// IE瀏覽器filename = URLEncoder.encode(filename, "utf-8");filename = filename.replace("+", " ");}else if (agent.contains("Firefox")){// 火狐瀏覽器filename = new String(fileName.getBytes(), "ISO8859-1");}else if (agent.contains("Chrome")){// google瀏覽器filename = URLEncoder.encode(filename, "utf-8");}else{// 其它瀏覽器filename = URLEncoder.encode(filename, "utf-8");}return filename;} }?
?
總結(jié)
以上是生活随笔為你收集整理的SpringBoot+ElementUI实现通用文件下载请求(全流程图文详细教程)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java中将String格式的标准时间字
- 下一篇: IDEA下SpringBoot项目的引用