SpringBoot框架如何实现上传与下载查看文件

基于SpringBoot框架,如何实现文件的上传与下载查看

提要

本项目借鉴于spring-guides/gs-uploading-files: Uploading Files :: Learn how to build a Spring application that accepts multi-part file uploads. (github.com)SpringBoot官网学习文档关于如何下载文件一章提供的演示代码;

GitHub

Download-File-Java: Demonstration How to implement file upload, client download, or view files under the springboot framework. (github.com)

本项目使用GitHub作为代码托管平台,友友们,点亮小星星是对博主莫大的支持哦!!!

演示环境

  • idea集成开发工具
  • JDK21
  • Apache Maven 3.9.4

接口设计

URL: http://localhost/files/{filename}

method: GET

query: filename-文件名

function: 查看文件

URL: http://localhost/files/download/{filename}

method: GET

query: filename-文件名

function: 下载文件

URL: http://localhost/upload

method: GET

param: file-多文件对象

function: 上传文件

单元测试

分别使用MockMvc与TestRestTemplate测试工具类,模拟客户端发送HTTP请求,对项目接口与存储服务层进行了测试;

项目文件

项目文件层次

具体实现

配置类

配置客户端上传到服务端的文件存储地址,博主是默认存放在存储静态文件的resources目录下;

@Value注解可以获取properties文件中存储的配置信息;

package test.springboot.demo.config;


import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;

/**
 * 配置存储
 **/
@Configuration
public class StorageConfigure {
    @Value("${storage.path}")
    private String location;

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

}

properties文件

存放配置的信息

spring.servlet.multipart.max-file-size=4MB
spring.servlet.multipart.max-request-size=4MB
storage.path=src/main/resources/localStorage

API层

package test.springboot.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.service.StorageService;

@Controller
public class FileUploadController {


    private final StorageService storageService;

    /**
     * 采用构造函数来注入StorageService对象,方便进行单测
     * @param storageService StorageService对象
     **/
     @Autowired
    public FileUploadController(StorageService storageService) {
        this.storageService = storageService;
    }

    // 与上面的构造函数一样,用于注入StorageService对象
    // @Autowired
    // private StorageService storageService;

    /**
     * 做代理,客户端可下载资源或查看资源
     * @return 文件后缀
     **/
    @GetMapping(value = {"/files/{filename:.+}", "/files/{download:.+}/{filename:.+}"})
    @ResponseBody
    public ResponseEntity<Resource> serveFile(@PathVariable(required = false) String download, @PathVariable String filename) {
        // 获取文件数据
        Resource file = storageService.loadAsResource(filename);
        // 如果文件为空就返回响应404
        if (file == null) {
            return ResponseEntity.notFound().build();
        }
        // 创建响应实体,设置状态码为200
        ResponseEntity.BodyBuilder req = ResponseEntity.status(HttpStatus.OK);
        // 如果download不为空,则执行下载,添加消息头attachment
        if (download!=null) {
            req.header(HttpHeaders.CONTENT_DISPOSITION,
                    "attachment; filename=\"" + file.getFilename() + "\"");
        }
        // 设置默认文件类型为application/octet-stream,二进制流
        String contentType = "application/octet-stream";
        if (file.getFilename() != null) {
            // 获得文件名后缀
            String ext = getFileExtension(file.getFilename());
            switch (ext) {
                case "pdf":
                    contentType = "application/pdf";
                    break;
                case "png", "gif", "jpg":
                    contentType = "image/" + ext;
                    break;
                case "jpeg":
                    contentType = "image/jpeg";
                    break;
                case "ofd", "zip":
                    contentType = "application/" + ext;
                    break;
                case "xlsx":
                    contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                    break;
            }
        }
        // 返回封装好的响应实体
        return req.contentType(MediaType.valueOf(contentType))
                .body(file);
    }

    /**
     * 获得文件名后缀
     * @param fileName 文件名
     * @return 文件后缀
     **/
    public String getFileExtension(String fileName) {
        if (fileName.lastIndexOf(".") != -1 && fileName.lastIndexOf(".") != 0)
            return fileName.substring(fileName.lastIndexOf(".") + 1);
        else
            return "";
    }

    /**
     * 上传文件
     * @return 上传是否成功
     */
    @PostMapping("/upload")
    @ResponseBody
    public boolean handleFileUpload(@RequestParam("file") MultipartFile file) {
        return storageService.store(file);
    }

    // 用于处理StorageFileNotFoundException异常。
    // 当抛出该异常时,函数会返回一个ResponseEntity对象,其状态码为404 Not Found,
    // 表示找不到指定的文件或资源。
    // 该函数通过@ExceptionHandler注解指定用于处理特定类型的异常
    @ExceptionHandler(StorageFileNotFoundException.class)
    public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) {
        return ResponseEntity.notFound().build();
    }

}

报错处理

针对存储数据失败,文件查询失败封装的异常信息;

package test.springboot.demo.exception;

/**
 * 封装'存储失败'异常信息
 **/
public class StorageException extends RuntimeException {

    /**
     * 构造函数
     * @param message 异常原因
     **/
    public StorageException(String message) {
        super(message);
    }
    
    /**
     * 构造函数
     * @param message 异常原因
     * @param cause 异常报错
     **/
    public StorageException(String message, Throwable cause) {
        super(message, cause);
    }
}
package test.springboot.demo.exception;

/**
 * 封装'文件未找到'异常信息
 **/
public class StorageFileNotFoundException extends StorageException {

    /**
     * 构造函数
     * @param message 异常原因
     **/
    public StorageFileNotFoundException(String message) {
        super(message);
    }

    /**
     * 构造函数
     * @param message 异常原因
     * @param cause 异常报错
     **/
    public StorageFileNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}

服务层接口

package test.springboot.demo.service;


import org.springframework.core.io.Resource;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.exception.StorageFileNotFoundException;

import java.nio.file.Path;
import java.util.stream.Stream;

public interface StorageService {
    /**
     * 初始化下载路径
     * @exception StorageException 存储异常
     **/
    void init();
    /**
     * 存储多文件对象到下载路径下
     * @param file MultipartFile类型的多文件对象
     * @return 是否存储成功
     * @exception StorageException 存储异常
     **/
    boolean store(MultipartFile file);
    /**
     * 获得下载路径下的所有文件Path流
     * @return Path文件流
     * @exception StorageException 存储异常
     **/
    Stream<Path> loadAll();
    /**
     * 获得Path文件路径
     * @param filename 文件名
     * @return Path文件路径
     **/
    Path load(String filename);
    /**
     * 获得文件资源
     * @param filename 文件名
     * @return 文件资源
     * @exception StorageFileNotFoundException 文件不存在异常
     **/
    Resource loadAsResource(String filename);
    /**
     * 删除下载路径文件夹及其路径下所有文件
     **/
    void deleteAll();

}

服务层实现

package test.springboot.demo.service.impl;


import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.stream.Stream;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.multipart.MultipartFile;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.config.StorageConfigure;
import test.springboot.demo.service.StorageService;

@Service
public class FileStorageServiceImpl implements StorageService {

    private final Path rootLocation;
    /**
     * 构造方法
     * @param properties StorageProperties对象
     **/
    @Autowired
    public FileStorageServiceImpl(StorageConfigure properties) {
        // 若下载路径为空,抛出异常
        if(properties.getLocation().trim().length() == 0){
            throw new StorageException("File upload location can not be Empty.");
        }
        // 设置下载路径
        this.rootLocation = Paths.get(properties.getLocation());
    }

    /**
     * 存储多文件对象到下载路径下
     * @param file MultipartFile类型的多文件对象
     * @return 是否存储成功
     * @exception StorageException 存储异常
     **/
    @Override
    public boolean store(MultipartFile file) {
        try {
            // 判断是否为空
            if (file.isEmpty()) {
                throw new StorageException("Failed to store empty file.");
            }

            Path destinationFile = this.rootLocation.resolve(
                            // Paths.get获取文件名并转为Path对象
                            Paths.get(file.getOriginalFilename()))
                    // 转为绝对路径
                    .normalize().toAbsolutePath();
            // 判断是否与期望的下载路径一致
            if (!destinationFile.getParent().equals(this.rootLocation.toAbsolutePath())) {
                // This is a security check
                throw new StorageException(
                        "Cannot store file outside current directory.");
            }
            // 拷贝文件,到下载路径
            try (InputStream inputStream = file.getInputStream()) {
                long size = Files.copy(inputStream, destinationFile,
                        StandardCopyOption.REPLACE_EXISTING);
                if (size > 0) {
                    return true;
                }
            }
        }
        catch (IOException e) {
            throw new StorageException("Failed to store file.", e);
        }
        return false;
    }

    /**
     * 获得下载路径下的所有文件Path流
     * @return Path文件流
     * @exception StorageException 存储异常
     **/
    @Override
    public Stream<Path> loadAll() {
        try {
            //获得下载路径下的深度为一的所有文件夹与文件
            return Files.walk(this.rootLocation, 1)
                    // 去掉下载路径的文件夹
                    .filter(path -> !path.equals(this.rootLocation))
                    // 返回处理成相对路径的Path流
                    .map(this.rootLocation::relativize);
        }
        catch (IOException e) {
            throw new StorageException("Failed to read stored files", e);
        }

    }

    /**
     * 获得Path文件路径
     * @param filename 文件名
     * @return Path文件路径
     **/
    @Override
    public Path load(String filename) {
        // 获得Path文件路径
        return rootLocation.resolve(filename);
    }

    /**
     * 获得文件资源
     * @param filename 文件名
     * @return 文件资源
     * @exception StorageFileNotFoundException 文件不存在异常
     **/
    @Override
    public Resource loadAsResource(String filename) {
        try {
            // Path 是 Java 7 引入的一个接口,它是 java.nio.file 包的一部分,用于表示文件系统中的路径。
            // Path 接口定义了一些基本的操作,而具体的实现类如 java.nio.file.Paths 提供了创建 Path 对象的方法。

            // 获得本地存储的此文件名的Path
            Path file = load(filename);
            // 获得文件URL,Resource是Spring Framework中的类,用于封装对资源的访问
            // toUri() 方法返回一个 URI 对象,表示文件可访问的网络位置
            Resource resource = new UrlResource(file.toUri());
            // 检测文件是否存在或可读
            if (resource.exists() || resource.isReadable()) {
                return resource;
            }
            else {
                throw new StorageFileNotFoundException(
                        "Could not read file: " + filename);

            }
        }
        catch (MalformedURLException e) {
            throw new StorageFileNotFoundException("Could not read file: " + filename, e);
        }
    }

    /**
     * 删除下载路径文件夹及其路径下所有文件
     **/
    @Override
    public void deleteAll() {
        // toFile()将下载路径转为File对象,并遍历删除所有文件
        FileSystemUtils.deleteRecursively(rootLocation.toFile());
    }

    /**
     * 初始化下载路径
     * @exception StorageException 存储异常
     **/
    @Override
    public void init() {
        try {
            // 创建下载路径文件夹,若该文件夹已经存在则不做任何操作
            Files.createDirectories(rootLocation);
        }
        catch (IOException e) {
            throw new StorageException("Could not initialize storage", e);
        }
    }
}

项目启动类

package test.springboot.demo;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import test.springboot.demo.service.StorageService;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
    }

    /**
     * 初始化存储,CommandLineRunner是Spring Boot提供的接口,允许在应用启动完成后执行一些操作
     * 实现该接口的方法会在应用启动后自动运行,通常用于执行启动时的任务,如数据初始化等
     * @param storageService-存储服务
     * @return
     **/
    @Bean
    CommandLineRunner init(StorageService storageService) {
       return (args) -> {
          storageService.deleteAll();
          storageService.init();
       };
    }
}

单元测试

测试本地存储服务
package test.springboot.demo.storage;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import test.springboot.demo.service.impl.FileStorageServiceImpl;
import test.springboot.demo.exception.StorageException;
import test.springboot.demo.config.StorageConfigure;

import java.util.Random;

import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
 * 用于测试本地文件存储的服务层
 **/
public class FileStorageServiceImplTests {

    private StorageConfigure properties = new StorageConfigure();
    private FileStorageServiceImpl service;

    @BeforeEach
    public void init() {
       properties.setLocation("src/main/resources/localStorage/files/" + Math.abs(new Random().nextLong()));
       service = new FileStorageServiceImpl(properties);
       service.init();
    }
    @AfterEach
    public void terminate() {
       properties.setLocation("src/main/resources/localStorage/files/");
       service = new FileStorageServiceImpl(properties);
       service.deleteAll();
    }

    @Test
    public void emptyUploadLocation() {
        service = null;
        properties.setLocation("");
        assertThrows(StorageException.class, () -> {
            service = new FileStorageServiceImpl(properties);
       });
    }

    @Test
    public void loadNonExistent() {
       assertThat(service.load("foo.txt")).doesNotExist();
    }

    @Test
    public void saveAndLoad() {
       service.store(new MockMultipartFile("admin", "admin.txt", MediaType.TEXT_PLAIN_VALUE,
             "I am cool boy!".getBytes()));
       assertThat(service.load("admin.txt")).exists();
    }

    @Test
    public void saveRelativePathNotPermitted() {
       assertThrows(StorageException.class, () -> {
          service.store(new MockMultipartFile("admin", "../admin.txt",
                MediaType.TEXT_PLAIN_VALUE, "I am cool boy!".getBytes()));
       });
    }

    @Test
    public void savePermitted() {
       service.store(new MockMultipartFile("amdin", "localStorage/../admin.txt",
             MediaType.TEXT_PLAIN_VALUE, "I am cool boy!".getBytes()));
    }

}
MockMvc测试文件上传下载
package test.springboot.demo;

import org.junit.jupiter.api.Test;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.web.servlet.MockMvc;
import test.springboot.demo.exception.StorageFileNotFoundException;
import test.springboot.demo.service.StorageService;

import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.then;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * 使用MockMvc测试
 **/
@AutoConfigureMockMvc
@SpringBootTest
public class FileMockMvcTests {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private StorageService storageService;

    /**
     * 测试上传文件
     **/
    @Test
    public void shouldSaveUploadedFile() throws Exception {
       MockMultipartFile multipartFile = new MockMultipartFile("file", "test.txt",
             "text/plain", "hello world".getBytes());
       this.mvc.perform(multipart("/upload").file(multipartFile))
             .andExpect(status().isOk());

       then(this.storageService).should().store(multipartFile);
    }

    /**
     * 测试文件不存在时抛出404错误
     * @throws Exception
     */
    @SuppressWarnings("unchecked") // 抑制编译器对方法体内可能出现的未经检查的警告
    @Test
    public void should404WhenMissingFile() throws Exception {
       given(this.storageService.loadAsResource("test.txt"))
             .willThrow(StorageFileNotFoundException.class);

       this.mvc.perform(get("/files/test.txt")).andExpect(status().isNotFound());
    }

}
TestRestTemplate测试文件上传下载
package test.springboot.demo;


import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import test.springboot.demo.service.StorageService;


import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.BDDMockito.given;

/**
 * 使用TestRestTemplate测试,模拟Spring Boot应用程序的运行环境,任意端口
 **/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class FileRestTemplateTests {

    // TestRestTemplate是Spring提供的一个简化HTTP请求的工具类,
    // 常用于集成测试中模拟客户端向服务端发送HTTP请求。
    // 在这个上下文中,它将被用来执行文件上传和下载的HTTP请求操作。
    @Autowired
    private TestRestTemplate restTemplate;

    // StorageService的mock对象,用于模拟存储服务,避免对实际服务层进行调用
    @MockBean
    private StorageService storageService;

    // 获得应用的端口,用于测试
    @LocalServerPort
    private int port;


    /**
     * 测试文件上传功能
     **/
    @Test
    public void shouldUploadFile() throws Exception {
       // 获得本地存储的的test.txt文件
       ClassPathResource resource = new ClassPathResource("test.txt");
       // 放入多文件集合请求中
       MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
       map.add("file", resource);
       // 执行上传操作
       ResponseEntity<String> response = this.restTemplate.postForEntity("/upload", map,
             String.class);
       // 判断是否存储文件成功
       assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
    }

    /**
     * 测试文件下载功能
     **/
    @Test
    public void shouldDownloadFile() throws Exception {
       // 获得本地存储的的test.txt文件
       ClassPathResource resource = new ClassPathResource("test.txt");
       // mock设定调用loadAsResource("test.txt")时返回本地存储的此文件
       given(this.storageService.loadAsResource("test.txt")).willReturn(resource);
       // 使用RestTemplate对象发起GET请求,下载文件,返回数据类型指定为string
       ResponseEntity<String> response = this.restTemplate
             .getForEntity("/files/{filename}", String.class, "test.txt");

       assertThat(response.getStatusCodeValue()).isEqualTo(200);
       assertThat(response.getBody()).isEqualTo("hello world!");
    }

}
pom.xml依赖管理
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>3.3.2</version>
       <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>test.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
       <license/>
    </licenses>
    <developers>
       <developer/>
    </developers>
    <scm>
       <connection/>
       <developerConnection/>
       <tag/>
       <url/>
    </scm>
    <properties>
       <java.version>21</java.version>
    </properties>
    <dependencies>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-thymeleaf</artifactId>
       </dependency>
       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
       </dependency>

       <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
       </dependency>
    </dependencies>

    <build>
       <plugins>
          <plugin>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
       </plugins>
    </build>

</project>

提醒

  • 客户端上传的文件均存放在resourceslocalStorage目录下,可以在application.properties文件内修改storage.path来更改下载路径;
  • 客户端上传的文件设置了最大文件大小4MB,可以在application.properties文件内修改最大文件大小;
  • resources下的learningRecord目录下存放了author的部分学习知识点,仅供参考;
  • 本项目为自行编写的代码,撰写了大量注释帮助理解代码。
  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现文件上传下载可以使用Servlet或SpringMVC框架,这里我为您提供SpringBoot框架的代码示例。 1. 文件上传: 在SpringBoot中,我们可以使用MultipartFile类来接收上传文件。以下是一个简单的文件上传示例: ```java @PostMapping("/upload") public String upload(@RequestParam("file") MultipartFile file) throws IOException { String fileName = file.getOriginalFilename(); String filePath = "/path/to/save/file/" + fileName; File dest = new File(filePath); file.transferTo(dest); return "success"; } ``` 其中,@PostMapping("/upload")表示接收POST请求,并映射到/upload路径;@RequestParam("file")表示接收名为"file"的文件参数,将其转化为MultipartFile类型;MultipartFile提供了transferTo方法,可以将上传文件保存到指定的文件路径中。 2. 文件下载: 在SpringBoot中,我们可以使用ResponseEntity类来实现文件下载。以下是一个简单的文件下载示例: ```java @GetMapping("/download") public ResponseEntity<byte[]> download() throws IOException { String filePath = "/path/to/download/file/"; File file = new File(filePath); HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData("attachment", file.getName()); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); return new ResponseEntity<>(FileUtils.readFileToByteArray(file), headers, HttpStatus.OK); } ``` 其中,@GetMapping("/download")表示接收GET请求,并映射到/download路径;HttpHeaders提供了setContentDispositionFormData方法,可以设置下载文件的名称;MediaType.APPLICATION_OCTET_STREAM表示以二进制流的形式下载文件。FileUtils.readFileToByteArray方法可以将指定文件读取为字节数组,最终使用ResponseEntity返回下载结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值