前端發(fā)送的請(qǐng)求Spring如何返回一個(gè)文件詳解
前言
因?yàn)楸救酥饕菍W(xué)習(xí)后端Java的,前端呢只是了解一點(diǎn)點(diǎn)基礎(chǔ)語法,所以本篇文章中可能會(huì)顯得有一些不專業(yè),所以呢,請(qǐng)大家多多包涵。
對(duì)于前后端交互的部分,我使用的最多的就是通過 Ajax 來像后端發(fā)送 HTTP 請(qǐng)求,但是呢,眾所周知,Ajax 默認(rèn)是不直接支持文件的下載的(即,它不能直接觸發(fā)瀏覽器的下載管理器),,你通常需要將文件內(nèi)容作為某種形式的數(shù)據(jù)(如Base64編碼的字符串或Blob)返回,并在前端處理這些數(shù)據(jù)以觸發(fā)下載或顯示文件內(nèi)容。
那么這篇文章,我將介紹如何對(duì)后端即將傳輸?shù)奈募鎏幚?,以至于我們的前端能夠得到這個(gè)文件。
如果文件可以通過URL訪問
如果我們要上傳的問價(jià)可以通過 URL 訪問的話,那么我們就可以使用 UrlResource
來對(duì)文件進(jìn)行處理:
import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.net.MalformedURLException; import java.nio.file.Paths; @RestController public class FileDownloadController { @GetMapping("/download") public ResponseEntity<Resource> downloadFile(@RequestParam String fileName) throws MalformedURLException { // 假設(shè)文件存儲(chǔ)在服務(wù)器上的某個(gè)目錄 String filePath = "/path/to/your/files/" + fileName; Resource file = new UrlResource(filePath); if (file.exists() || file.isReadable()) { // 設(shè)置HTTP頭以支持文件下載 HttpHeaders headers = new HttpHeaders(); headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\""); headers.add(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate"); headers.add(HttpHeaders.PRAGMA, "no-cache"); headers.add(HttpHeaders.EXPIRES, "0"); return ResponseEntity.ok() .headers(headers) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(file); } else { // 處理文件不存在或不可讀的情況 return ResponseEntity.notFound().build(); } } }
- 設(shè)置了Content-Disposition為attachment,這通常用于提示瀏覽器將響應(yīng)作為文件下載。但是,如果你希望圖片直接在瀏覽器中顯示,可能不需要這個(gè)設(shè)置。
- CACHE_CONTROL 這個(gè)請(qǐng)求頭就是緩存控制
- expires 過期時(shí)間
注意我們這個(gè)類的返回類型需是 ResponseEntity<>
,該類用于構(gòu)建 HTTP 響應(yīng)。響應(yīng)中的 contentType 用來設(shè)置我們返回的 body 是什么類型,MediaType 類中有很多的靜態(tài)類型:
public class MediaType extends MimeType implements Serializable { private static final long serialVersionUID = 2069937152339670231L; public static final MediaType ALL = new MediaType("*", "*"); public static final String ALL_VALUE = "*/*"; public static final MediaType APPLICATION_ATOM_XML = new MediaType("application", "atom+xml"); public static final String APPLICATION_ATOM_XML_VALUE = "application/atom+xml"; public static final MediaType APPLICATION_CBOR = new MediaType("application", "cbor"); public static final String APPLICATION_CBOR_VALUE = "application/cbor"; public static final MediaType APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded"); public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded"; public static final MediaType APPLICATION_GRAPHQL = new MediaType("application", "graphql+json"); public static final String APPLICATION_GRAPHQL_VALUE = "application/graphql+json"; public static final MediaType APPLICATION_JSON = new MediaType("application", "json"); public static final String APPLICATION_JSON_VALUE = "application/json"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_JSON_UTF8; /** @deprecated */ @Deprecated public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"; public static final MediaType APPLICATION_OCTET_STREAM; public static final String APPLICATION_OCTET_STREAM_VALUE = "application/octet-stream"; public static final MediaType APPLICATION_PDF; public static final String APPLICATION_PDF_VALUE = "application/pdf"; public static final MediaType APPLICATION_PROBLEM_JSON; public static final String APPLICATION_PROBLEM_JSON_VALUE = "application/problem+json"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_PROBLEM_JSON_UTF8; /** @deprecated */ @Deprecated public static final String APPLICATION_PROBLEM_JSON_UTF8_VALUE = "application/problem+json;charset=UTF-8"; public static final MediaType APPLICATION_PROBLEM_XML; public static final String APPLICATION_PROBLEM_XML_VALUE = "application/problem+xml"; public static final MediaType APPLICATION_RSS_XML; public static final String APPLICATION_RSS_XML_VALUE = "application/rss+xml"; public static final MediaType APPLICATION_NDJSON; public static final String APPLICATION_NDJSON_VALUE = "application/x-ndjson"; /** @deprecated */ @Deprecated public static final MediaType APPLICATION_STREAM_JSON; /** @deprecated */ @Deprecated public static final String APPLICATION_STREAM_JSON_VALUE = "application/stream+json"; public static final MediaType APPLICATION_XHTML_XML; public static final String APPLICATION_XHTML_XML_VALUE = "application/xhtml+xml"; public static final MediaType APPLICATION_XML; public static final String APPLICATION_XML_VALUE = "application/xml"; public static final MediaType IMAGE_GIF; public static final String IMAGE_GIF_VALUE = "image/gif"; public static final MediaType IMAGE_JPEG; public static final String IMAGE_JPEG_VALUE = "image/jpeg"; public static final MediaType IMAGE_PNG; public static final String IMAGE_PNG_VALUE = "image/png"; public static final MediaType MULTIPART_FORM_DATA; public static final String MULTIPART_FORM_DATA_VALUE = "multipart/form-data"; public static final MediaType MULTIPART_MIXED; public static final String MULTIPART_MIXED_VALUE = "multipart/mixed"; public static final MediaType MULTIPART_RELATED; public static final String MULTIPART_RELATED_VALUE = "multipart/related"; public static final MediaType TEXT_EVENT_STREAM; public static final String TEXT_EVENT_STREAM_VALUE = "text/event-stream"; public static final MediaType TEXT_HTML; public static final String TEXT_HTML_VALUE = "text/html"; public static final MediaType TEXT_MARKDOWN; public static final String TEXT_MARKDOWN_VALUE = "text/markdown"; public static final MediaType TEXT_PLAIN; public static final String TEXT_PLAIN_VALUE = "text/plain"; public static final MediaType TEXT_XML; public static final String TEXT_XML_VALUE = "text/xml"; private static final String PARAM_QUALITY_FACTOR = "q"; }
大家可以根據(jù)自己要返回的文件的具體類型來選擇。
后端對(duì)文件進(jìn)行處理了之后,前端也是需要做出調(diào)整的,由于 Ajax 默認(rèn)不支持文件的下載,所以我們選擇使用 fetch 來作為 web api。
什么是fetch
這里的解釋來自于百度:
fetch 是 Web API 的一部分,它提供了一種簡單、邏輯清晰的方式來跨網(wǎng)絡(luò)異步獲取資源(包括文件、網(wǎng)絡(luò)請(qǐng)求等)。fetch API 返回一個(gè) Promise,這個(gè) Promise 解析為一個(gè) Response 對(duì)象,該對(duì)象包含來自服務(wù)器的各種響應(yīng)信息,比如響應(yīng)頭、狀態(tài)碼等,并且允許你訪問響應(yīng)體(response body)的內(nèi)容。
與 XMLHttpRequest 相比,fetch 提供了一個(gè)更現(xiàn)代、更簡潔的API來訪問和操作網(wǎng)絡(luò)請(qǐng)求和響應(yīng)。fetch 支持 Promise API,這使得異步邏輯更加容易編寫和理解。
fetch 處理文件更加的方便,所以這里我們選擇使用 fetch。
function downloadFile(url, fileName) { fetch(url, { method: 'post', // 可以添加其他必要的請(qǐng)求頭,如認(rèn)證信息等 headers: { // 示例:'Authorization': 'Bearer your_token_here' }, // 告訴瀏覽器我們期望的響應(yīng)類型是一個(gè)Blob responseType: 'blob' }) .then(response => { // 檢查響應(yīng)是否成功 if (!response.ok) { throw new Error('Network response was not ok'); } // 返回Blob對(duì)象 return response.blob(); }) .then(blob => { // 創(chuàng)建一個(gè)指向該Blob的URL // 我們可以通過這個(gè)生成的URL訪問到這個(gè)文件 const url = window.URL.createObjectURL(blob); // 我這里就直接將圖片的URL給用了 let pic = document.querySelector('.main .left .user .picture') pic.style.backgroundImage = 'url(' + url + ')' // 這個(gè)用于將生成的URL給清除掉,我們這里可以先不清, //如果清除了的話,前端可能無法通過這個(gè)URL獲取到這個(gè)文件, //我們可以在關(guān)閉頁面的時(shí)候調(diào)用這個(gè)方法 // 清理工作 // window.URL.revokeObjectURL(url); }) .catch(error => { console.error('There has been a problem with your fetch operation:', error); }); }
如果文件無法通過URL訪問到
如果文件不是通過URL訪問到的,例如它們存儲(chǔ)在文件系統(tǒng)中的話,就需要依靠 FileSystemResource
等其他資源類。
@RequestMapping("/getUserPic") public ResponseEntity<Resource> getUserPic(String fileName) { //獲取到存儲(chǔ)在文件系統(tǒng)中的文件 Resource resource = new FileSystemResource(Constant.path + fileName); return ResponseEntity.ok() .contentType(MediaType.IMAGE_JPEG) .header(HttpHeaders.CONTENT_DISPOSITION,"attachment; filename=" + resource.getFilename()) .body(resource);}
然后前端呢就還是通過 fetch 來為文件創(chuàng)建一個(gè)指向該文件的URL,就可以通過這個(gè)URL訪問了。
如果使用了AOP對(duì)返回結(jié)果做了處理
如果我們的Spring使用了AOP來對(duì)返回結(jié)果進(jìn)行了統(tǒng)一處理的話,對(duì)于返回的 ResponseEntity<>
我們還需要做出調(diào)整:
@ControllerAdvice public class ResponseAdvice implements ResponseBodyAdvice { @Autowired private ObjectMapper objectMapper; @Override public boolean supports(MethodParameter returnType, Class converterType) { return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { //調(diào)整在這里,如果返回的類型是Resource的時(shí)候就直接返回 if (body instanceof Resource) { return body; } if (body instanceof String) { try { return objectMapper.writeValueAsString(body); } catch (JsonProcessingException e) { throw new RuntimeException(e); } }else if (body instanceof Result) { return body; }else { return Result.success(body); } } }
總結(jié)
到此這篇關(guān)于前端發(fā)送的請(qǐng)求Spring如何返回一個(gè)文件的文章就介紹到這了,更多相關(guān)前端發(fā)送請(qǐng)求Spring返回文件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot?加載本地jar到maven的實(shí)現(xiàn)方法
如何在SpringBoot項(xiàng)目中加載本地jar到Maven本地倉庫,使用Maven的install-file目標(biāo)來實(shí)現(xiàn),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-01-01SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱
緩存預(yù)熱是指在 Spring Boot 項(xiàng)目啟動(dòng)時(shí),預(yù)先將數(shù)據(jù)加載到緩存系統(tǒng)(如 Redis)中的一種機(jī)制,本文主要介紹了SpringBoot如何實(shí)現(xiàn)緩存預(yù)熱,感興趣的可以了解下2024-12-12Java fastjson解析json字符串實(shí)現(xiàn)過程解析
這篇文章主要介紹了Java fastjson解析json字符串實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn)
Redis提供了哨兵模式來處理主從切換和故障轉(zhuǎn)移,本文主要介紹了SpringBoot整合Redis的哨兵模式的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08Spring Data JPA實(shí)現(xiàn)分頁P(yáng)ageable的實(shí)例代碼
本篇文章主要介紹了Spring Data JPA實(shí)現(xiàn)分頁P(yáng)ageable的實(shí)例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07java使用URLDecoder和URLEncoder對(duì)中文字符進(jìn)行編碼和解碼
這篇文章主要介紹了java 使用 URLDecoder 和 URLEncoder 對(duì)中文字符進(jìn)行編碼和解碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07