1. 程式人生 > 實用技巧 >檔案上傳和下載

檔案上傳和下載

application.properties

## MULTIPART (MultipartProperties)
# 開啟 multipart 上傳功能
spring.servlet.multipart.enabled=true
# 檔案寫入磁碟的閾值
spring.servlet.multipart.file-size-threshold=2KB
# 最大檔案大小
spring.servlet.multipart.max-file-size=200MB
# 最大請求大小
spring.servlet.multipart.max-request-size=215MB

## 檔案儲存所需引數
# 所有通過 REST APIs 上傳的檔案都將儲存在此目錄下
file.uploadDir=C:\\Users\\Yuri\\Desktop\\TRY

FileService

package yuri.newfile.demo.service;

import org.springframework.core.io.UrlResource;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import yuri.newfile.demo.pojo.FileProperties;
import yuri.newfile.demo.util.FileException;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Service
public class FileService {

    private final Path fileStorageLocation;

    @Autowired
    public FileService(FileProperties fileProperties) {
        this.fileStorageLocation = Paths.get(fileProperties.getUploadDir()).toAbsolutePath().normalize();
        try {
            Files.createDirectories(this.fileStorageLocation);
        } catch (Exception e) {
            throw new FileException("不能建立上傳檔案儲存路徑");
        }
    }

    public String storeFile(MultipartFile file) {
//        file.getOriginalFilename()返回檔名,但某些瀏覽器下會返回帶碟符的路徑,所以用StringUtils.cleanPath()進行處理
        String fileName = StringUtils.cleanPath(file.getOriginalFilename());

        try{
//            檢查檔名是否含有非法字元
            if (fileName.contains("..")){
                throw new FileException("檔名含有非法字元");
            }

//            resolve()把儲存路徑fileStorageLocation和檔名fileName合併為一條路徑
//            C:\Users\Yuri\Desktop\TRY+xxx = C:\Users\Yuri\Desktop\TRY\xxx
            Path path = this.fileStorageLocation.resolve(fileName);

//            對檔案進行儲存操作,三個引數分別是輸入流、路徑、(列舉)操作引數
            Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
            return fileName;
        }catch (IOException e){
            throw new FileException("不能儲存檔案:" + fileName);
        }
    }

    public Resource loadFileAsResource(String fileName) {
        try{
            Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());

//            System.out.println(filePath);
//            System.out.println(filePath.toUri());
//            System.out.println(resource);
            if(resource.exists()){
                return resource;
            }else{
                throw new FileException("未找到檔案:" + fileName);
            }
        } catch (MalformedURLException e) {
            throw new FileException("未找到檔案:" + fileName, e);
        }
    }
}

FileController

package yuri.newfile.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import yuri.newfile.demo.service.FileService;
import yuri.newfile.demo.util.UploadFileResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.naming.Context;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.web.servlet.function.RequestPredicates.contentType;

@RestController
public class FileController {
    private static final Logger logger = LoggerFactory.getLogger(FileController.class);

    @Autowired
    private FileService fileService;

    @PostMapping("/uploadFile")
    public UploadFileResponse uploadFileResponse(@RequestParam("file")MultipartFile file){
//        對檔案進行儲存操作
        String fileName = fileService.storeFile(file);

//        對返回引數進行設定
//        ServletUriComponentsBuilder構建Url地址,
//        fromCurrentContextPath()為本機IP,比如http://localhost:8080
//        path是對後續路徑進行增添
//        toUrlString是進行Url地址轉義,因為起初構建的並不是標準url地址
        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();

//        返回此次傳輸的UploadFileResponse物件
        return new UploadFileResponse(fileName, fileDownloadUri,
                file.getContentType(), file.getSize());
    }

    @PostMapping("/uploadFiles")
    public List<UploadFileResponse> uploadFileResponses(@RequestParam("files") MultipartFile[] files){
//        Java8新特性:Stream()將陣列轉換為流,map()是過濾操作,此處過濾方法為uploadFileResponse,collect(Collectors.toList())是固定寫法,將結果轉為List
        return Arrays.stream(files)
                .map(this::uploadFileResponse)
                .collect(Collectors.toList());
    }

    @GetMapping("/downloadFile/{fileName:.+}")
//    @PathVariable可以把url{}中變數賦值給引數,當不寫value就對應名字自動賦值
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request){
        Resource resource = fileService.loadFileAsResource(fileName);

        String contentType = null;
        try{
//            getMimeType()獲取檔案的格式,是ServletContext的一個方法
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException e){
            logger.info("不能確定檔案型別");
        }

        if (contentType == null) {
            contentType = "application/octet-stream";
        }
        
//        進行檔案下載處理
        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"" +resource.getFilename() + "\"")
                .body(resource);
    }
}

程式碼參考

https://www.jianshu.com/p/e25b3c542553