对于前端发送的请求,Spring如何返回一个文件
不能再留遗憾了 2024-09-02 16:33:01 阅读 85
文章目录
前言如果文件可以通过URL访问什么是fetch
如果文件无法通过URL访问到如果使用了AOP对返回结果做了处理
前言
因为本人主要是学习后端Java的,前端呢只是了解一点点基础语法,所以本篇文章中可能会显得有一些不专业,所以呢,请大家多多包涵。
对于前后端交互的部分,我使用的最多的就是通过 Ajax 来像后端发送 HTTP 请求,但是呢,众所周知,Ajax 默认是不直接支持文件的下载的(即,它不能直接触发浏览器的下载管理器),,你通常需要将文件内容作为某种形式的数据(如Base64编码的字符串或Blob)返回,并在前端处理这些数据以触发下载或显示文件内容。
那么这篇文章,我将介绍如何对后端即将传输的文件做处理,以至于我们的前端能够得到这个文件。
如果文件可以通过URL访问
如果我们要上传的问价可以通过 URL 访问的话,那么我们就可以使用 <code>UrlResource 来对文件进行处理:
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 {
// 假设文件存储在服务器上的某个目录
String filePath = "/path/to/your/files/" + fileName;
Resource file = new UrlResource(filePath);
if (file.exists() || file.isReadable()) {
// 设置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();
}
}
}
设置了Content-Disposition为attachment,这通常用于提示浏览器将响应作为文件下载。但是,如果你希望图片直接在浏览器中显示,可能不需要这个设置。CACHE_CONTROL 这个请求头就是缓存控制expires 过期时间
注意我们这个类的返回类型需是 ResponseEntity<>
,该类用于构建 HTTP 响应。响应中的 contentType 用来设置我们返回的 body 是什么类型,MediaType 类中有很多的静态类型:
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";
}
大家可以根据自己要返回的文件的具体类型来选择。
后端对文件进行处理了之后,前端也是需要做出调整的,由于 Ajax 默认不支持文件的下载,所以我们选择使用 fetch 来作为 web api。
什么是fetch
这里的解释来自于百度:
fetch 是 Web API 的一部分,它提供了一种简单、逻辑清晰的方式来跨网络异步获取资源(包括文件、网络请求等)。fetch API 返回一个 Promise,这个 Promise 解析为一个 Response 对象,该对象包含来自服务器的各种响应信息,比如响应头、状态码等,并且允许你访问响应体(response body)的内容。
与 XMLHttpRequest 相比,fetch 提供了一个更现代、更简洁的API来访问和操作网络请求和响应。fetch 支持 Promise API,这使得异步逻辑更加容易编写和理解。
fetch 处理文件更加的方便,所以这里我们选择使用 fetch。
function downloadFile(url, fileName) {
fetch(url, {
method: 'post',
// 可以添加其他必要的请求头,如认证信息等
headers: {
// 示例:'Authorization': 'Bearer your_token_here'
},
// 告诉浏览器我们期望的响应类型是一个Blob
responseType: 'blob'
})
.then(response => {
// 检查响应是否成功
if (!response.ok) {
throw new Error('Network response was not ok');
}
// 返回Blob对象
return response.blob();
})
.then(blob => {
// 创建一个指向该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获取到这个文件,
//我们可以在关闭页面的时候调用这个方法
// 清理工作
// window.URL.revokeObjectURL(url);
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error);
});
}
如果文件无法通过URL访问到
如果文件不是通过URL访问到的,例如它们存储在文件系统中的话,就需要依靠 FileSystemResource
等其他资源类。
@RequestMapping("/getUserPic")
public ResponseEntity<Resource> getUserPic(String fileName) {
//获取到存储在文件系统中的文件
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 来为文件创建一个指向该文件的URL,就可以通过这个URL访问了。
如果使用了AOP对返回结果做了处理
如果我们的Spring使用了AOP来对返回结果进行了统一处理的话,对于返回的 ResponseEntity<>
我们还需要做出调整:
@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) {
//调整在这里,如果返回的类型是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);
}
}
}
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。