前端發(fā)送的請求Spring如何返回一個文件詳解
前言
因為本人主要是學(xué)習(xí)后端Java的,前端呢只是了解一點點基礎(chǔ)語法,所以本篇文章中可能會顯得有一些不專業(yè),所以呢,請大家多多包涵。
對于前后端交互的部分,我使用的最多的就是通過 Ajax 來像后端發(fā)送 HTTP 請求,但是呢,眾所周知,Ajax 默認(rèn)是不直接支持文件的下載的(即,它不能直接觸發(fā)瀏覽器的下載管理器),,你通常需要將文件內(nèi)容作為某種形式的數(shù)據(jù)(如Base64編碼的字符串或Blob)返回,并在前端處理這些數(shù)據(jù)以觸發(fā)下載或顯示文件內(nèi)容。
那么這篇文章,我將介紹如何對后端即將傳輸?shù)奈募鎏幚?,以至于我們的前端能夠得到這個文件。
如果文件可以通過URL訪問
如果我們要上傳的問價可以通過 URL 訪問的話,那么我們就可以使用 UrlResource 來對文件進(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è)文件存儲在服務(wù)器上的某個目錄
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)作為文件下載。但是,如果你希望圖片直接在瀏覽器中顯示,可能不需要這個設(shè)置。
- CACHE_CONTROL 這個請求頭就是緩存控制
- expires 過期時間
注意我們這個類的返回類型需是 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ù)自己要返回的文件的具體類型來選擇。
后端對文件進(jìn)行處理了之后,前端也是需要做出調(diào)整的,由于 Ajax 默認(rèn)不支持文件的下載,所以我們選擇使用 fetch 來作為 web api。
什么是fetch
這里的解釋來自于百度:
fetch 是 Web API 的一部分,它提供了一種簡單、邏輯清晰的方式來跨網(wǎng)絡(luò)異步獲取資源(包括文件、網(wǎng)絡(luò)請求等)。fetch API 返回一個 Promise,這個 Promise 解析為一個 Response 對象,該對象包含來自服務(wù)器的各種響應(yīng)信息,比如響應(yīng)頭、狀態(tài)碼等,并且允許你訪問響應(yīng)體(response body)的內(nèi)容。
與 XMLHttpRequest 相比,fetch 提供了一個更現(xiàn)代、更簡潔的API來訪問和操作網(wǎng)絡(luò)請求和響應(yīng)。fetch 支持 Promise API,這使得異步邏輯更加容易編寫和理解。
fetch 處理文件更加的方便,所以這里我們選擇使用 fetch。
function downloadFile(url, fileName) {
fetch(url, {
method: 'post',
// 可以添加其他必要的請求頭,如認(rèn)證信息等
headers: {
// 示例:'Authorization': 'Bearer your_token_here'
},
// 告訴瀏覽器我們期望的響應(yīng)類型是一個Blob
responseType: 'blob'
})
.then(response => {
// 檢查響應(yīng)是否成功
if (!response.ok) {
throw new Error('Network response was not ok');
}
// 返回Blob對象
return response.blob();
})
.then(blob => {
// 創(chuàng)建一個指向該Blob的URL
// 我們可以通過這個生成的URL訪問到這個文件
const url = window.URL.createObjectURL(blob);
// 我這里就直接將圖片的URL給用了
let pic = document.querySelector('.main .left .user .picture')
pic.style.backgroundImage = 'url(' + url + ')'
// 這個用于將生成的URL給清除掉,我們這里可以先不清,
//如果清除了的話,前端可能無法通過這個URL獲取到這個文件,
//我們可以在關(guān)閉頁面的時候調(diào)用這個方法
// 清理工作
// window.URL.revokeObjectURL(url);
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
}
如果文件無法通過URL訪問到
如果文件不是通過URL訪問到的,例如它們存儲在文件系統(tǒng)中的話,就需要依靠 FileSystemResource 等其他資源類。
@RequestMapping("/getUserPic")
public ResponseEntity<Resource> getUserPic(String fileName) {
//獲取到存儲在文件系統(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)建一個指向該文件的URL,就可以通過這個URL訪問了。
如果使用了AOP對返回結(jié)果做了處理
如果我們的Spring使用了AOP來對返回結(jié)果進(jìn)行了統(tǒng)一處理的話,對于返回的 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的時候就直接返回
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ā)送的請求Spring如何返回一個文件的文章就介紹到這了,更多相關(guān)前端發(fā)送請求Spring返回文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot?加載本地jar到maven的實現(xiàn)方法
如何在SpringBoot項目中加載本地jar到Maven本地倉庫,使用Maven的install-file目標(biāo)來實現(xiàn),本文結(jié)合實例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2025-01-01
Java fastjson解析json字符串實現(xiàn)過程解析
這篇文章主要介紹了Java fastjson解析json字符串實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-10-10
SpringBoot整合Redis的哨兵模式的實現(xiàn)
Redis提供了哨兵模式來處理主從切換和故障轉(zhuǎn)移,本文主要介紹了SpringBoot整合Redis的哨兵模式的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-08-08
Spring Data JPA實現(xiàn)分頁Pageable的實例代碼
本篇文章主要介紹了Spring Data JPA實現(xiàn)分頁Pageable的實例代碼,具有一定的參考價值,有興趣的可以了解一下2017-07-07
java使用URLDecoder和URLEncoder對中文字符進(jìn)行編碼和解碼
這篇文章主要介紹了java 使用 URLDecoder 和 URLEncoder 對中文字符進(jìn)行編碼和解碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07

