基於SpringWeb MultipartFile文件上傳、下載功能

来源:https://www.cnblogs.com/JavaEdge/p/18139938
-Advertisement-
Play Games

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


在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 發佈!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄一、httptest1.1 前置代碼準備1.2 介紹1.3 基本用法二、gock2.1介紹2.2 安裝2.3 基本使用2.4 舉個例子2.4.1 前置代碼2.4.2 測試用例 一、httptest 1.1 前置代碼準備 假設我們的業務邏輯是搭建一個http server端,對外提供HTTP服務。 ...
  • 什麼是觀察者 觀察者模式的主要角色包括: 主題(Subject): 也稱為被觀察者或可觀察對象。它維護了一系列觀察者對象,並提供方法用於註冊、刪除和通知觀察者。當主題的狀態發生改變時,它會通知所有註冊的觀察者。 觀察者(Observer): 觀察主題的對象。觀察者定義了一個更新方法,主題在狀態改變時 ...
  • 在 Python 中,迭代器是一種非常好用的數據結構,其最大的優勢就是延遲生成,按需使用,從而大大提高程式的運行效率。而 itertools 作為 Python 的內置模塊,就為我們提供了一套非常有用的用於操作可迭代對象的函數。 常用功能 1.count 功能詳解 count(start=0,ste ...
  • operator 模塊提供了一套與 Python 的內置運算符對應的高效率函數。 1.函數的種類 函數包含的種類有:對象的比較運算、邏輯運算、數學運算和序列運算 2.比較運算 運算 函數 語法 小於 lt(a, b) a < b 小於等於 le(a, b) a <= b 大於 gt(a, b) a ...
  • 試用阿裡雲GPU伺服器進行深度學習模型訓練 最近在用PyTorch時發現在本地訓練模型速度一言難盡,然後發現阿裡雲可以白嫖gpu伺服器,只要沒有申請過PAI-DSW資源的新老用戶都可以申請5000CU*H的免費額度,三個月內有效。 阿裡雲免費試用活動頁面 一、申請試用並創建實例 點擊試用,完成註冊、 ...
  • Problem: 28. 找出字元串中第一個匹配項的下標 目錄解題方法思路構建next數組回溯查找複雜度Code 解題方法 構建next串 回溯查找next串,最後下標 思路 通過最大首碼尾碼能找到下一次未查找到後要回溯的位置 構建next數組 無論如何第一個數的下一次回溯位置肯定是0,因此next ...
  • 背景及問題說明 使用 Kafka client 版本 3.4.0 目前的預設分區策略如下: NOTE this partitioner is deprecated and shouldn't be used. To use default partitioning logic remove part ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
一周排行
    -Advertisement-
    Play Games
  • PasteSpider是什麼? 一款使用.net編寫的開源的Linux容器部署助手,支持一鍵發佈,平滑升級,自動伸縮, Key-Value配置,項目網關,環境隔離,運行報表,差量升級,私有倉庫,集群部署,版本管理等! 30分鐘上手,讓開發也可以很容易的學會在linux上部署你得項目! [從需求角度介 ...
  • SQLSugar是什麼 **1. 輕量級ORM框架,專為.NET CORE開發人員設計,它提供了簡單、高效的方式來處理資料庫操作,使開發人員能夠更輕鬆地與資料庫進行交互 2. 簡化資料庫操作和數據訪問,允許開發人員在C#代碼中直接操作資料庫,而不需要編寫複雜的SQL語句 3. 支持多種資料庫,包括但 ...
  • 在C#中,經常會有一些耗時較長的CPU密集型運算,因為如果直接在UI線程執行這樣的運算就會出現UI不響應的問題。解決這類問題的主要途徑是使用多線程,啟動一個後臺線程,把運算操作放在這個後臺線程中完成。但是原生介面的線程操作有一些難度,如果要更進一步的去完成線程間的通訊就會難上加難。 因此,.NET類 ...
  • 一:背景 1. 講故事 前些天有位朋友在微信上丟了一個崩潰的dump給我,讓我幫忙看下為什麼出現了崩潰,在 Windows 的事件查看器上顯示的是經典的 訪問違例 ,即 c0000005 錯誤碼,不管怎麼說有dump就可以上windbg開幹了。 二:WinDbg 分析 1. 程式為誰崩潰了 在 Wi ...
  • CSharpe中的IO+NPOI+序列化 文件文件夾操作 學習一下常見的文件、文件夾的操作。 什麼是IO流? I:就是input O:就是output,故稱:輸入輸出流 將數據讀入記憶體或者記憶體輸出的過程。 常見的IO流操作,一般說的是[記憶體]與[磁碟]之間的輸入輸出。 作用 持久化數據,保證數據不再 ...
  • C#.NET與JAVA互通之MD5哈希V2024 配套視頻: 要點: 1.計算MD5時,SDK自帶的計算哈希(ComputeHash)方法,輸入輸出參數都是byte數組。就涉及到字元串轉byte數組轉換時,編碼選擇的問題。 2.輸入參數,字元串轉byte數組時,編碼雙方要統一,一般為:UTF-8。 ...
  • CodeWF.EventBus,一款靈活的事件匯流排庫,實現模塊間解耦通信。支持多種.NET項目類型,如WPF、WinForms、ASP.NET Core等。採用簡潔設計,輕鬆實現事件的發佈與訂閱。通過有序的消息處理,確保事件得到妥善處理。簡化您的代碼,提升系統可維護性。 ...
  • 一、基本的.NET框架概念 .NET框架是一個由微軟開發的軟體開發平臺,它提供了一個運行時環境(CLR - Common Language Runtime)和一套豐富的類庫(FCL - Framework Class Library)。CLR負責管理代碼的執行,而FCL則提供了大量預先編寫好的代碼, ...
  • 本章將和大家分享在ASP.NET Core中如何使用高級客戶端NEST來操作我們的Elasticsearch。 NEST是一個高級別的Elasticsearch .NET客戶端,它仍然非常接近原始Elasticsearch API的映射。所有的請求和響應都是通過類型來暴露的,這使得它非常適合快速上手 ...
  • 參考delphi的代碼更改為C# Delphi 檢測密碼強度 規則(仿 google) 仿 google 評分規則 一、密碼長度: 5 分: 小於等於 4 個字元 10 分: 5 到 7 字元 25 分: 大於等於 8 個字元 二、字母: 0 分: 沒有字母 10 分: 全都是小(大)寫字母 20 ...