SpringBoot上传与下载文件

news2024/12/29 15:29:48

使用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.coloradmin.cn/o/1181190.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iconfont 图标使用

&#xff08;1&#xff09;在阿里巴巴矢量图标库注册账号&#xff0c;然后让同伴拉你进项目iconfont-阿里巴巴矢量图标库 &#xff08;2) 点击资源管理 - 我的项目 - 可以看见该项目的图标了 &#xff08;3&#xff09;点击上传图标至项目 - 可以上传图标 使用图标 &#x…

使用高德地图获取定位报错:INVALID_USER_SCODE(无效用户代码)

1. 确定自己已经申请了相关应用的key&#xff0c;这里有两个key 一个是应用的Key&#xff0c;一个是安全密钥 2. 应用key一般是发送请求的是后通过key"xxx"发送 3. 安全密钥要在head里加入进去 <script type"text/javascript">window._AMapSecuri…

CocosCreator使用物理引擎和回调

在2d中开启碰撞需要在项目设置–功能裁剪–2D物理系统【选择 基于Box2D的2D物理系统】 如果想要两个物体碰撞&#xff0c;则需要添加刚体和碰撞【&#xff01;&#xff01;重点】 设置刚体类型 可以设为四种&#xff0c; Static 静态刚体&#xff0c;零质量&#xff0c;零速度…

《微服务架构设计模式》之三:微服务架构中的进程通信

概述 交互方式 客户端和服务端交互方式可以从两个维度来分&#xff1a; 维度1&#xff1a;一对一和多对多 一对一&#xff1a;每个客户端请求由一个实例来处理。 一对多&#xff1a;每个客户端请求由多个实例来处理。维度2&#xff1a;同步和异步 同步模式&#xff1a;客户端…

如何评价现在的CSGO游戏搬砖市场

如何评价现在的csgo市场&#xff1f; 其实整个搬砖市场&#xff0c;现在已经变得乌烟瘴气&#xff0c;散发着“恶臭”。我个人非常鄙视那些虚有其表&#xff0c;大小通吃的做法&#xff0c;那些甚至连搬砖数据都看不懂的人&#xff0c;也出来吹嘘着“实力强大&#xff0c;经验丰…

[架构之路-244]:目标系统 - 设计方法 - 软件工程 - 软件开发方法:结构化、面向对象、面向服务、面向组件的开发方法

目录 前言&#xff1a; 一、概述: 软件聚合的程度由简单到复杂 二、主要开发方法详见 2.1 结构化的开发方法 2.2 面对对象的开发方法 2.3 面向服务的开发方法 2.4 面向组件的开发方法 三、不同开发方法比较 3.1 结构化开发方法 3.2 面向对象(OOP)开发方法 3.3 面向服…

电源模块测试科普:如何检测电源模块的功率?测试方法是什么?

电源模块功率的重要性 功率是电源模块的一个重要指标。电源模块功率描述了电源的输出能力&#xff0c;即电源模块为电路或设备提供电能的大小&#xff0c;通常用来衡量电源模块的性能和效率。 电源功率直接影响着电子设备的性能和功能。电源模块功率越高&#xff0c;提供的电能…

模块化之CJS, AMD, UMD 和 ESM

[[toc]] 模块化优点 防止命名冲突代码复用高维护性CJS, AMD, UMD 和 ESM 历史 ES6之前,JS一直没有自己的模块体系后来社区出现了CommonJS和AMD,CommonJS 主要用于服务器(Node)AMD 主要用于浏览器ES6引入了ESM到此,JS终于有了自己的模块体系,基本上可以完全取代CJS和AMD…

TCP流量控制和拥塞控制

文章目录 流量控制拥塞控制 流量控制 当发送方发送速率大于接收方的处理速率时&#xff0c;接收方会把数据包放入缓冲区&#xff0c;当缓冲区满了&#xff0c;就只能将数据包丢弃。为了应对这种情况&#xff0c;流量控制就可以大展身手了 流量控制的作用对象是发送方和接收方 …

【计算文献解读】ACS Catal.:塑料垃圾回收利用中的均相催化

合理的塑料回收对于解决与塑料垃圾相关的环境挑战至关重要&#xff0c;而在各种回收方法中&#xff0c;化学回收&#xff0c;特别是通过均相催化&#xff0c;有望将塑料垃圾转化为有价值的产品。由于聚烯烃链的结构不均匀性和功能化&#xff0c;聚合物废物对催化循环提出了挑战…

AI人工智能大模型业务到底有多烧钱?

AI大模型业务确实是一个非常烧钱的行业。首先&#xff0c;大模型的训练需要大量的计算资源。 这些模型通常由数百万个参数组成&#xff0c;训练它们需要大量的计算能力和存储空间。这意味着公司需要购买大量的高性能服务器、图形处理单元和存储设备&#xff0c;这些都是非常昂…

Nvidia显卡Failed to initialize NVML Driver/library version mismatch错误解决方案

最近GPT比较火&#xff0c;开始折腾了一下gpu,用来跑项目&#xff1a; https://github.com/OpenTalker/SadTalker 今天运行程序突然发现用不了&#xff0c;经排查应该是由于NVIDIA内核驱动版本与系统驱动版本不一致导致的。 下面简单总结了这个错误的解决方案。 问题复现 查看…

如何规划并新建大数据平台的独立生产域?5步走

一般来说&#xff0c;大数据平台包括以下4类数据生产域——生产生态环境&#xff08;正式生产环境&#xff09;、开发和测试环境、培训和演示环境、灾备环境。各生产域在由平台提供资源、安全、监控、故障恢复等保障的同时&#xff0c;不同的生产域之间还需要严格隔离&#xff…

宏观角度认识递归之 Pow(x,n) 问题

50. Pow(x, n) - 力扣&#xff08;LeetCode&#xff09; 计算 x 的 n 次幂&#xff0c;如果是直接暴力求解的话&#xff0c;会造成计算时间周期过长&#xff0c;所以要从别的角度出发&#xff0c;将幂等数分为两个幂等数相乘&#xff0c;例如&#xff1a;三的八次方&#xff0c…

Python基础入门(19)----Python单元测试基础:unittest模块的基本使用

文章目录 创建测试用例测试套件断言运行测试测试固件Python的unittest模块是基于Java的JUnit框架开发出来的,提供了编写和运行单元测试的工具。这篇文章将介绍unittest模块的基本使用,涵盖创建测试用例、测试套件、断言、运行测试以及测试固件的使用。 创建测试用例 在unit…

货币转换

维护货币汇率 事务代码&#xff1a;OB08 调用BAPI CALL FUNCTION BAPI_EXCHANGERATE_GETDETAILEXPORTINGrate_type Mfrom_curr ls_ekko-waersto_currncy CNYdate sy-datumIMPORTINGexch_rate ls_exch_ratereturn ls_return.ls_zsmm043-header-rmb_price …

python解析xmind统计测试用例/测试点 个数及执行情况

前言&#xff1a;统计的是每个分支最后一个节点的状态 xmind版本 23.0911172 标记打开位置 标记规则如下 解释&#xff1a; res {"total": 0, "pass": 0, "fail": 0, "no_result": 0, "unfinished": 0, "now_fail…

MCU测试科普|如何进行MCU芯片测试,具体流程是什么?

MCU芯片测试系统是一种专门用于检测MCU芯片性能和质量的综合性设备。它通常由硬件和软件两部分组成&#xff0c;硬件包括测试仪器、适配器、测试夹具等&#xff0c;用于连接被测MCU芯片和测试机&#xff0c;实现高效高精度的测试。软件部分通常包括测试程序、测试管理软件等&am…

安全狗连续5年零失误守护金鸡奖颁奖典礼安全

11月4日&#xff0c;第36届中国电影金鸡奖颁奖典礼暨2023年中国金鸡百花电影节闭幕式在厦门圆满落幕。 作为国内云原生安全领导厂商&#xff0c;安全狗再一次收到客户委托&#xff0c;为其颁奖活动期间的相关宣传窗口、网页和系统的网络安全全程护航。 01 台上幕后 荣耀守护 …

openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果

文章目录 openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果117.1 前提条件117.2 背景信息117.3 操作步骤 openGauss学习笔记-117 openGauss 数据库管理-设置数据库审计-查看审计结果 117.1 前提条件 审计功能总开关已开启。需要审计的审计项开关已开…