前端发送的请求Spring如何返回一个文件详解
前言
因为本人主要是学习后端Java的,前端呢只是了解一点点基础语法,所以本篇文章中可能会显得有一些不专业,所以呢,请大家多多包涵。
对于前后端交互的部分,我使用的最多的就是通过 Ajax 来像后端发送 HTTP 请求,但是呢,众所周知,Ajax 默认是不直接支持文件的下载的(即,它不能直接触发浏览器的下载管理器),,你通常需要将文件内容作为某种形式的数据(如Base64编码的字符串或Blob)返回,并在前端处理这些数据以触发下载或显示文件内容。
那么这篇文章,我将介绍如何对后端即将传输的文件做处理,以至于我们的前端能够得到这个文件。
如果文件可以通过URL访问
如果我们要上传的问价可以通过 URL 访问的话,那么我们就可以使用 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); } } }
总结
到此这篇关于前端发送的请求Spring如何返回一个文件的文章就介绍到这了,更多相关前端发送请求Spring返回文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
基于spring+springmvc+hibernate 整合深入剖析
这篇文章主要介绍了于spring+springmvc+hibernate整合实例,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-10-10SpringBoot ThreadLocal 简单介绍及使用详解
ThreadLocal 叫做线程变量,意思是 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量,这篇文章主要介绍了SpringBoot ThreadLocal 的详解,需要的朋友可以参考下2024-01-01SpringCloud Gateway 路由配置定位原理分析
本节主要了解系统中的谓词与配置的路由信息是如何进行初始化关联生成路由对象的。每个谓词工厂中的Config对象又是如何被解析配置的2021-07-07SpringBoot日程管理Quartz与定时任务Task实现详解
定时任务是企业级开发中必不可少的组成部分,诸如长周期业务数据的计算,例如年度报表,诸如系统脏数据的处理,再比如系统性能监控报告,还有抢购类活动的商品上架,这些都离不开定时任务。本节将介绍两种不同的定时任务技术2022-09-09
最新评论