基於SpringWeb MultipartFile檔案上傳、下載功能

公众号-JavaEdge發表於2024-04-17

在Web開發中,檔案上傳是一個常見的功能需求。Spring框架提供了MultipartFile介面,用於處理檔案上傳請求。MultipartFile可以代表一個多部分檔案上傳請求中的一個檔案,提供了一系列方法用於獲取檔案的各種屬性和內容,使得在後端處理檔案上傳變得十分方便。下面我們將介紹MultipartFile在Web應用中的幾種常見使用場景。

1. 圖片上傳

在Web應用中,圖片上傳是一種常見的場景。使用者需要上傳頭像、相片、證件照等圖片檔案,而後端需要接收並儲存這些檔案。使用MultipartFile介面可以輕鬆地實現圖片檔案的接收和處理。透過獲取檔案的原始檔名、內容型別、大小等屬性,我們可以實現對圖片檔案的有效管理和儲存。例如,我們可以將圖片檔案儲存到伺服器的檔案系統中,或者將其儲存到雲端儲存服務中。

2. 檔案下載

除了檔案上傳,檔案下載也是Web應用中常見的功能需求。使用MultipartFile介面,我們可以實現檔案的下載功能。在伺服器端,我們可以將檔案作為MultipartFile物件進行處理,並透過設定響應頭資訊,將檔案作為下載內容返回給客戶端。客戶端接收到檔案後,可以將其儲存到本地磁碟或進行其他處理。

3. 檔案編輯

在Web應用中,有時候使用者需要對上傳的檔案進行編輯操作,例如修改檔名、修改檔案內容等。使用MultipartFile介面,我們可以實現對檔案的編輯功能。首先,我們可以透過MultipartFile介面獲取上傳的檔案物件,然後對其進行相應的編輯操作。例如,我們可以修改檔案的名稱、修改檔案的內容等。編輯完成後,我們可以將修改後的檔案儲存到伺服器或返回給客戶端。

4. 檔案預覽和展示

在Web應用中,有時候我們需要將上傳的檔案進行預覽或展示。例如,在文件管理系統中,使用者需要預覽或下載文件檔案。使用MultipartFile介面,我們可以實現檔案的預覽和展示功能。我們可以將檔案作為MultipartFile物件進行處理,然後將其內容轉換為適當的格式進行展示。例如,對於PDF檔案,我們可以使用PDF閱讀器外掛進行展示;對於圖片檔案,我們可以將其直接展示在網頁上。

5. 檔案批次上傳和處理

在實際應用中,有時候使用者需要批次上傳多個檔案,並對這些檔案進行處理。使用MultipartFile介面,我們可以實現檔案的批次上傳和處理功能。我們可以將多個檔案作為一個多部分檔案上傳請求進行處理,然後對每個檔案進行相應的操作。例如,我們可以將多個圖片檔案批次上傳到伺服器,並對它們進行壓縮、裁剪等處理。

程式碼

package com.javagpt.back.controller;

import com.javagpt.application.context.UserAppContextHolder;
import com.javagpt.application.file.FileApplicationService;
import com.javagpt.application.file.FileDTO;
import com.javagpt.common.annotation.RespSuccess;
import com.javagpt.common.constant.EMConstant;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

@Api(tags = "檔案介面")
@Slf4j
@RestController
@RequestMapping(EMConstant.API_V1 + "/file")
@RespSuccess
@RequiredArgsConstructor
public class FileController {

    private final FileApplicationService fileApplicationService;

    @ApiOperation("通用檔案上傳")
    @PostMapping(value = "/uploadFile")
    public FileDTO uploadFile(@RequestParam("file") MultipartFile multipartFile) throws IOException {
        Long enterpriseId = UserAppContextHolder.getCurrentUser().getEnterpriseId();
        FileDTO fileDTO = fileApplicationService.saveFile(enterpriseId, multipartFile);
        return fileDTO;
    }

    //@PreAuthorize("hasAuthority('mp:file:download')")
    @ApiOperation("下載檔案")
    @GetMapping(value = "/downloadFile")
    public void download(@RequestParam(value = "id") Long id, HttpServletResponse response) throws IOException {
        fileApplicationService.downloadFile(response, id, UserAppContextHolder.getCurrentUser().getEnterpriseId());
    }

    @ApiOperation("檢視檔案資訊")
    @GetMapping(value = "/info")
    public FileDTO fileInfo(@RequestParam(value = "id") Long id) throws IOException {
        return fileApplicationService.findById(id);
    }

    @ApiOperation("下載影片")
    @GetMapping(value = "/downloadFile2")
    public void download2(@RequestParam(value = "id") Long id, HttpServletRequest request, HttpServletResponse response) throws IOException {
        fileApplicationService.downloadVideo(request, response, id, UserAppContextHolder.getCurrentUser().getEnterpriseId());
    }
}
package com.javagpt.application.file;

import com.javagpt.common.exception.BusinessRuntimeException;
import com.javagpt.common.oos.OssService;
import com.javagpt.common.util.ModelUtils;
import com.javagpt.common.util.SpringResponseUtils;
import com.javagpt.file.entity.FileEntity;
import com.javagpt.file.repository.FileRepository;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class FileApplicationService {

    private final OssService ossService;

    private final FileRepository fileRepository;


    public FileDTO findById(Long id) {
        FileEntity fileEntity = fileRepository.findById(id);
        return ModelUtils.convert(fileEntity, FileDTO.class);
    }

    @Transactional
    public FileDTO saveFile(Long enterpriseId, MultipartFile file) {
        FileEntity fileEntity = saveFile(enterpriseId, file, null);
        return ModelUtils.convert(fileEntity, FileDTO.class);
    }

    @Transactional
    public FileEntity saveFile(Long enterpriseId, MultipartFile file, String fileName) {
        String originalFilename = file.getOriginalFilename();
        String name = StringUtils.isBlank(fileName) ? FilenameUtils.getBaseName(originalFilename) : fileName;
        String suffix = FilenameUtils.getExtension(originalFilename);
        long size = file.getSize();
        FileEntity fileEntity = new FileEntity();
        fileEntity.setName(name).setSuffix(suffix).setSize(size).setEnterpriseId(enterpriseId);
        fileEntity = fileEntity.save();
        String key = fileEntity.getPath();
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
        } catch (IOException e) {
            log.error("saveFile error:", e);
            throw BusinessRuntimeException.error("上傳檔案失敗");
        }
        ossService.uploadFile(inputStream, key);
        IOUtils.closeQuietly(inputStream);
        return fileEntity;
    }


    @Transactional
    public FileEntity saveFile(File file) {
        long size = file.length();
        FileEntity fileEntity = new FileEntity();
        String baseName = FilenameUtils.getBaseName(file.getName());
        String extension = FilenameUtils.getExtension(file.getName());
        fileEntity.setName(baseName).setSuffix(extension).setSize(size);
        fileEntity = fileEntity.save();
        String key = fileEntity.getPath();
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            ossService.uploadFile(inputStream, key);
        } catch (FileNotFoundException e) {
            log.error("saveFile error:", e);
            throw BusinessRuntimeException.error("上傳檔案失敗");
        }
        IOUtils.closeQuietly(inputStream);
        return fileEntity;
    }


    public void downloadFile(HttpServletResponse response, Long fileId, Long enterpriseId) throws IOException {
        FileEntity fileEntity = fileRepository.findById(fileId);
        if (fileEntity == null) {
            throw BusinessRuntimeException.error("無效的檔案Id");
        }
        String key = fileEntity.getPath();
        InputStream inputStream = ossService.downloadFile(key);
        SpringResponseUtils.writeAndFlushResponse(inputStream, response, fileEntity.fileFullName());
    }


    public void downloadVideo(HttpServletRequest request, HttpServletResponse response, Long fileId, Long enterpriseId) throws IOException {

        FileEntity fileEntity = fileRepository.findById(fileId);
        if (fileEntity == null) {
            throw BusinessRuntimeException.error("無效的檔案Id");
        }
        response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
        Long fileSize = fileEntity.getSize();
        long start = 0, end = fileSize - 1;
        //判斷前端需不需要分片下載
        if (StringUtils.isNotBlank(request.getHeader("Range"))) {
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            String numRange = request.getHeader("Range").replaceAll("bytes=", "");
            String[] strRange = numRange.split("-");
            if (strRange.length == 2) {
                start = Long.parseLong(strRange[0].trim());
                end = Long.parseLong(strRange[1].trim());
                //若結束位元組超出檔案大小 取檔案大小
                if (end > fileSize - 1) {
                    end = fileSize - 1;
                }
            } else {
                //若只給一個長度  開始位置一直到結束
                start = Long.parseLong(numRange.replaceAll("-", "").trim());
            }
        }
        long rangeLength = end - start + 1;
        String contentRange = new StringBuffer("bytes ").append(start).append("-").append(end).append("/").append(fileSize).toString();
        response.setHeader(HttpHeaders.CONTENT_RANGE, contentRange);
        response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(rangeLength));
        String key = fileEntity.getPath();
        InputStream inputStream = ossService.downloadFile2(key, start, end);
        SpringResponseUtils.writeAndFlushResponse(inputStream, response, fileEntity.fileFullName());
    }
}

總之,MultipartFile介面在Web應用中具有廣泛的應用場景,可以實現檔案上傳、下載、編輯、預覽和批次處理等功能。透過熟練掌握MultipartFile介面的使用方法和技巧,我們可以更加高效地處理檔案上傳和下載請求,提升Web應用的使用者體驗和功能效能。

本文由部落格一文多發平臺 OpenWrite 釋出!

相關文章