当前位置:首页 » 《资源分享》 » 正文

对于前端发送的请求,Spring如何返回一个文件

27 人参与  2024年09月13日 08:01  分类 : 《资源分享》  评论

点击全文阅读


文章目录

前言如果文件可以通过URL访问什么是fetch 如果文件无法通过URL访问到如果使用了AOP对返回结果做了处理

前言

因为本人主要是学习后端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<> 我们还需要做出调整:

@ControllerAdvicepublic 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);        }    }}

点击全文阅读


本文链接:http://zhangshiyu.com/post/159075.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1