当前位置: 首页 > news >正文

SpringBoot上传与下载文件

使用SpringBoot的虚拟路径映射。

Config中的类

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * 图片绝对地址与虚拟地址映射
 */

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Value("${realityFileDepositPath}")
    private String realityFileDepositPath;

    @Value("${virtualFileDepositPath}")
    private String virtualFileDepositPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler(virtualFileDepositPath)
                .addResourceLocations("file:" + realityFileDepositPath);
    }
}

Control中的类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import xin.students.service.UpdateOrDownloadService;

@RestController
public class UpdateOrDownloadController {

    @Autowired
    UpdateOrDownloadService updateOrDownloadService;

    @PostMapping("/api/upload")
    public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
        return updateOrDownloadService.handleFileUpload(file);
    }

    @GetMapping("/api/upload/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) {
        return updateOrDownloadService.downloadFile(fileName);
    }
}

Service中的类

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;

@Service
public class UpdateOrDownloadService {

    @Value("${virtualFileDepositPath}")
    private String virtualFileDepositPath;

    @Value("${realityFileDepositPath}")
    private String realityFileDepositPath;


    public ResponseEntity<String> handleFileUpload(@RequestParam("file") MultipartFile file) {
        // 获取文件名
        String fileName = file.getOriginalFilename();

        // 确保文件名存在并且不是.exe文件
        if (fileName != null && !fileName.toLowerCase().endsWith(".exe")) {
            fileName = System.currentTimeMillis() + fileName;
            // 检查文件大小是否合适
            if (file.getSize() <= 10 * 1024 * 1024) { // 10 MB
                // 保存文件
                try {
                    String fullPath = realityFileDepositPath + fileName;
                    file.transferTo(new File(fullPath));
                    System.out.println("Public document has been saved to: " + fullPath);
                } catch (IOException e) {
                    e.printStackTrace();
                    return new ResponseEntity<>("Public document upload failed due to internal error", HttpStatus.INTERNAL_SERVER_ERROR);
                }
                // 返回文件访问虚拟路径
                return new ResponseEntity<>(virtualFileDepositPath.substring(0, virtualFileDepositPath.length() - 2) + fileName, HttpStatus.OK);
            } else {
                return new ResponseEntity<>("Public document size exceeds 10MB", HttpStatus.BAD_REQUEST);
            }
        } else {
            // 提供一个不同的错误消息
            return new ResponseEntity<>("Public document format is not supported or is executable, which is not allowed", HttpStatus.BAD_REQUEST);
        }
    }

    public ResponseEntity<Resource> downloadFile(String fileName) {
        try {
            // 确定文件的存储路径
            Path filePath = Paths.get(realityFileDepositPath).resolve(fileName).normalize();
            Resource resource = new UrlResource(filePath.toUri());
            if(resource.exists() || resource.isReadable()) {
                // 确保文件名编码正确,避免乱码
                String encodedFileName = URLEncoder.encode(resource.getFilename(), StandardCharsets.UTF_8.toString());
                String contentDisposition = ContentDisposition.builder("attachment")
                        .filename(encodedFileName, StandardCharsets.UTF_8)
                        .build()
                        .toString();

                return ResponseEntity.ok()
                        .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition)
                        .body(resource);
            } else {
                return ResponseEntity.notFound().build();
            }
        } catch (IOException e) {
            // 如果无法读取文件,返回错误响应
            return ResponseEntity.internalServerError().build();
        }
    }
}

application.yml配置文件

virtualFileDepositPath: /api/image/**
realityFileDepositPath: D:\xinFiles\ #结束必须要带/

测试代码

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>文件上传和下载</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            flex-direction: column;
        }
        .container {
            text-align: center;
        }
        input[type="text"], input[type="file"] {
            margin: 10px 0;
        }
    </style>
    <script>
        function uploadFile() {
            var formData = new FormData();
            var fileField = document.querySelector("input[type=file]");

            formData.append('file', fileField.files[0]);

            fetch('/api/upload', {
                method: 'POST',
                body: formData
            })
                .then(response => response.text())
                .then(result => {
                    alert('上传成功: ' + result);
                })
                .catch(error => {
                    console.error('上传出错:', error);
                    alert('上传失败');
                });
        }

        function downloadFile() {
            var fileName = document.getElementById("filename").value;
            if (fileName) {
                window.open('/api/upload/' + fileName, '_blank');
            } else {
                alert('请输入文件名');
            }
        }
    </script>
</head>
<body>
<div class="container">
    <h1>文件上传</h1>
    <input type="file" id="fileInput"><br>
    <button onclick="uploadFile()">上传文件</button>

    <h1>文件下载</h1>
    <input type="text" id="filename" placeholder="请输入文件名"><br>
    <button onclick="downloadFile()">下载文件</button>
</div>
</body>
</html>

http://www.dtcms.com/a/3704.html

相关文章:

  • 如何对ppt文件设置修改权限?
  • Django初窥门径-oauth登录认证
  • C++线程库的基本使用(初级)
  • RabbitMQ
  • 【MATLAB源码-第68期】基于matlab的802.11b 11Mbps CCK调制解调误码率仿真。
  • MapReduce性能优化之小文件问题和数据倾斜问题解决方案
  • javascript 算术运算符,比较运算符 ,逻辑运算符
  • WPF布局控件之DockPanel布局
  • 【计算机网络】数据链路层-MAC和ARP协议
  • 【C++】开源:rapidjson数据解析库配置与使用
  • 数据结构大体体系
  • 没网络也能安装.Net 3.5!如何脱机安装.NET Framework 3.5
  • 云尘 命令执行系列
  • 配置阿里云镜像加速器 -docker
  • 硬件加速器及其深度神经网络模型的性能指标理解
  • [算法日志]图论: 广度优先搜索(BFS)
  • NtripShare Caster高精度定位CORS服务软件
  • 【实践篇】一次Paas化热部署实践分享 | 京东云技术团队
  • 图像切分:将一张长图片切分为指定长宽的多张图片
  • element-ui 表格 点击选中
  • 中文大语言模型汇总
  • 城市内涝解决方案:实时监测,提前预警,让城市更安全
  • ESXi配置两个不同网段虚拟机互通
  • 考研408-计算机网络 第一章-计算机网络体系结构学习笔记及习题
  • 工具介绍——第三方软件远程连接(工具:Rustdesk)
  • 长短期神经网络LSTM的博文分类,长短期神经网络的原理分析
  • 【开题报告】基于uniapp的在线考试小程序的设计与实现
  • Python武器库开发-常用模块之subprocess模块(十九)
  • 技术分享 | App常见bug解析
  • CVE-2023-34040 Kafka 反序列化RCE