二、Web服务常用的I/O操作

news2025/7/16 11:05:19

一、单个或者批量上传文件

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传示例</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
            line-height: 1.6;
        }
        button {
            padding: 10px 15px;
            background-color: #4CAF50;
            color: white;
            border: none;
            cursor: pointer;
            font-size: 16px;
        }
        button:hover {
            background-color: #45a049;
        }
        #result {
            margin-top: 20px;
            padding: 10px;
            border: 1px solid #ddd;
            background-color: #f9f9f9;
        }
    </style>
</head>
<body>
    <h1>文件上传</h1>
    
    <h2>单个文件上传</h2>
    <form id="singleUploadForm">
        <input type="file" id="singleFileInput" name="file" required>
        <button type="button" onclick="uploadSingleFile()">上传文件</button>
    </form>
    
    <h2>批量文件上传</h2>
    <form id="batchUploadForm">
        <input type="file" id="batchFileInput" name="files" multiple required>
        <button type="button" onclick="uploadBatchFiles()">上传文件</button>
    </form>
    
    <div id="result"></div>

    <script>
        function uploadSingleFile() {
            const fileInput = document.getElementById('singleFileInput');
            const file = fileInput.files[0];
            
            if (!file) {
                alert('请选择一个文件');
                return;
            }

            const formData = new FormData();
            formData.append('file', file);

            fetch('http://localhost:8888/test/uploadFile', {
                method: 'POST',
                body: formData
            })
            .then(response => response.text())
            .then(data => {
                document.getElementById('result').innerHTML = data;
            })
            .catch(error => {
                document.getElementById('result').innerHTML = '上传失败: ' + error.message;
            });
        }

        function uploadBatchFiles() {
            const fileInput = document.getElementById('batchFileInput');
            const files = fileInput.files;
            
            if (!files || files.length === 0) {
                alert('请选择至少一个文件');
                return;
            }

            const formData = new FormData();
            for (let i = 0; i < files.length; i++) {
                formData.append('files', files[i]);
            }

            fetch('http://localhost:8888/test/uploadFiles', {
                method: 'POST',
                body: formData
            })
            .then(response => response.text())
            .then(data => {
                document.getElementById('result').innerHTML = data;
            })
            .catch(error => {
                document.getElementById('result').innerHTML = '上传失败: ' + error.message;
            });
        }
    </script>
</body>
</html>

在这里插入图片描述

后端:

 @PostMapping("test/uploadFile")
    public String upload(@RequestParam("file") MultipartFile file) {
        try {
            // 指定保存路径
            String savePath = "C:\\Users\\test\\Desktop\\";

            // 获取原始文件名
            String originalFilename = file.getOriginalFilename();

            if (originalFilename == null || originalFilename.isEmpty()) {
                return "文件名不能为空!";
            }

            // 构建完整路径
            Path targetPath = Paths.get(savePath + originalFilename);

            // 确保目录存在
            Files.createDirectories(targetPath.getParent());

            // 保存文件(替换已存在文件)
            Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);

            return "文件上传成功!保存路径: " + targetPath.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return "文件上传失败: " + e.getMessage();
        }
    }

    @PostMapping("/test/uploadFiles")
    public String uploadFiles(@RequestParam("files") MultipartFile[] files) {
        try {
            String savePath = "C:\\Users\\test\\Desktop\\";

            List<String> uploadedFiles = Arrays.stream(files)
                    .map(file -> {
                        try {
                            String originalFilename = file.getOriginalFilename();
                            if (originalFilename == null || originalFilename.isEmpty()) {
                                return "文件名不能为空!";
                            }

                            Path targetPath = Paths.get(savePath + originalFilename);
                            Files.createDirectories(targetPath.getParent());
                            Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
                            return "文件上传成功!保存路径: " + targetPath.toString();
                        } catch (IOException e) {
                            return "文件上传失败: " + e.getMessage();
                        }
                    })
                    .collect(Collectors.toList());

            return String.join("<br>", uploadedFiles);
        } catch (Exception e) {
            e.printStackTrace();
            return "文件上传失败: " + e.getMessage();
        }
    }

springboot要配置下文件上传大小限制:

# 设置单个文件的最大上传大小 (默认是1M)
spring.servlet.multipart.max-file-size=50MB
# 设置请求中所有文件的最大上传大小  (默认是10M)
spring.servlet.multipart.max-request-size=1000MB

二、后端上传文件

小文件处理,全部加载到内存

@GetMapping("/test/backUpload")
    public void backUpload() {

        String uploadUrl = "http://localhost:8888/test/uploadFile";
        String sourcePath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";

        Path filePath = Paths.get(sourcePath);

        if (!Files.exists(filePath)) {
            System.out.println("文件不存在!");
            return;
        }

        try {
            byte[] fileBytes = Files.readAllBytes(filePath); // NIO读取文件内容到byte数组

            ByteArrayResource resource = new ByteArrayResource(fileBytes) {
                @Override
                public String getFilename() {
                    return filePath.getFileName().toString();
                }
            };

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
            body.add("file", resource);

            HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);

            ResponseEntity<String> response = new RestTemplate().postForEntity(uploadUrl, requestEntity, String.class);
            System.out.println("上传结果:" + response.getBody());

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

大文件处理使用webflux流式处理

<dependency>
   <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
 @GetMapping("/test/backUploadNew")
    public void backUploadNew() {

        String uploadUrl = "http://localhost:8888/test/uploadFile";
        String sourcePath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";

        Path filePath = Paths.get(sourcePath);

        if (!Files.exists(filePath)) {
            System.out.println("文件不存在!");
            return;
        }

        try {
            InputStream inputStream = Files.newInputStream(filePath);

            InputStreamResource resource = new InputStreamResource(inputStream) {
                @Override
                public String getFilename() {
                    return filePath.getFileName().toString();
                }

                @Override
                public long contentLength() throws IOException {
                    return Files.size(filePath);
                }
            };

            MultipartBodyBuilder builder = new MultipartBodyBuilder();
            builder.part("file", resource)
                    .header("Content-Disposition", "form-data; name=file; filename=" + filePath.getFileName());

            HttpClient httpClient = HttpClient.create();
            ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);
            WebClient webClient = WebClient.builder()
                    .clientConnector(connector)
                    .build();

            webClient.method(HttpMethod.POST)
                    .uri(uploadUrl)
                    .contentType(MediaType.MULTIPART_FORM_DATA)
                    .bodyValue(builder.build())
                    .retrieve()
                    .bodyToMono(String.class)
                    .doOnNext(result -> System.out.println("上传结果:" + result))
                    .block(); // 等待上传完成

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

三、前端下载文件

前端直接访问接口 /test/download 下载

@GetMapping("/test/download")
    public void download(HttpServletResponse response) throws IOException {
        // 文件路径
        Path filePath = Paths.get("C:\\Users\\test\\Desktop\\哈哈+ +c.txt"); // 替换成你的实际路径

        if (Files.exists(filePath)) {
            response.setContentType("application/octet-stream");
            String fileName = filePath.getFileName().toString();
            // 处理中文文件名:防止下载时乱码
            String encodedFileName = java.net.URLEncoder.encode(fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-Disposition",
                    "attachment; filename=\"" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + "\"; filename*=UTF-8''" + encodedFileName);
            // 直接用 Files.copy,拷贝文件到 response 的输出流
            Files.copy(filePath, response.getOutputStream());
            response.flushBuffer(); // 刷新缓冲区,确保数据发出去
        } else {
            response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件未找到!");
        }
    }

四、后端下载文件

@GetMapping("/test/backDownload")
    public void backDownload() {
        String url = "http://localhost:8888/test/download";
        String destinationPath = "C:\\Users\\test\\Desktop\\ttt\\666.txt";

        try {
            ResponseEntity<Resource> response =  new RestTemplate().getForEntity(url, Resource.class);

            if (response.getStatusCode().is2xxSuccessful() && response.getBody() != null) {
                Path path = Paths.get(destinationPath);
                Files.createDirectories(path.getParent()); // 确保父目录存在
                Files.copy(response.getBody().getInputStream(), path);
                System.out.println("下载完成!");
            } else {
                System.out.println("下载失败,状态码:" + response.getStatusCode());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2345569.html

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

相关文章

「Mac畅玩AIGC与多模态04」开发篇01 - 创建第一个 LLM 对话应用

一、概述 本篇介绍如何在 macOS 环境下&#xff0c;基于已部署完成的 Dify 平台和本地 LLM 模型&#xff08;如 DeepSeek&#xff09;&#xff0c;创建并测试第一个基础对话应用&#xff0c;实现快速验证推理服务与平台交互功能。 二、应用创建流程 1. 通过首页创建应用 打…

深度探究获取淘宝商品数据的途径|API接口|批量自动化采集商品数据

在电商行业竞争日益激烈的今天&#xff0c;淘宝商品数据如同蕴藏巨大价值的宝藏&#xff0c;无论是商家进行竞品分析、优化商品策略&#xff0c;还是数据分析师挖掘市场趋势&#xff0c;都离不开对这些数据的获取与分析。本文将深入探讨获取淘宝商品数据的多种途径&#xff0c;…

马哥教育Linux云计算运维课程

课程大小&#xff1a;19.1G 课程下载&#xff1a;https://download.csdn.net/download/m0_66047725/90640128 更多资源下载&#xff1a;关注我 你是否找了很多资料看了很多视频聊了很多群友&#xff0c;却发现自己技术仍然原地踏步&#xff1f;本教程联合BAT一线导师倾囊相授…

FPGA与边缘AI:计算革命的前沿力量

在数字化转型浪潮中&#xff0c;边缘计算和人工智能正引领着技术革命。而FPGA&#xff08;现场可编程门阵列&#xff09;作为一种独特的硬件架构&#xff0c;正逐渐成为边缘AI领域的关键推动力。本文将探讨FPGA与边缘AI的结合如何重塑我们的数字世界&#xff0c;以及这一技术融…

Kafka 架构设计和组件介绍

什么是Apache Kafka&#xff1f; Apache Kafka 是一个强大的开源分布式事件流平台。它最初由 LinkedIn 开发&#xff0c;最初是一个消息队列&#xff0c;后来发展成为处理各种场景数据流的工具。 Kafka 的分布式系统架构支持水平扩展&#xff0c;使消费者能够按照自己的节奏检…

【Node.js 】在Windows 下搭建适配 DPlayer 的轻量(简陋)级弹幕后端服务

一、引言 DPlayer官网&#xff1a;DPlayer 官方弹幕后端服务&#xff1a;DPlayer-node MoePlayer/DPlayer-node&#xff1a;使用 Docker for DPlayer Node.js 后端&#xff08;https://github.com/DIYgod/DPlayer&#xff09; 本来想直接使用官网提供的DPlayer-node直接搭建…

OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理

OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理 目录 OpenSSH配置连接远程服务器MS ODBC驱动与Navicat数据库管理 一、MS ODBC驱动 1.1、安装到Windows后的表现形式 1.2、版本的互斥性 1.3、安装程序 1.4、配置后才可用 二、Navicat数据库管理工具 2.1、安…

操作系统:计算机世界的基石与演进

一、操作系统的本质与核心功能 操作系统如同计算机系统的"总管家"&#xff0c;在硬件与应用之间架起关键桥梁。从不同视角观察&#xff0c;其核心功能呈现多维价值&#xff1a; 硬件视角的双重使命&#xff1a; 硬件管理者&#xff1a;通过内存管理、进程调度和设…

Codeium 免费的AI编程助手

Codeium 由 Exafunction 团队&#xff08;主要也是美国华人&#xff09;开发的一款免费AI编程助手&#xff0c;是一个建立在顶尖AI技术上的代码加速工具&#xff0c;其背后的老板非常厉害&#xff0c;据说投资过马斯克的SpaceX。Codeium 本身具有颇多的亮点&#xff0c;支持70种…

在MySQL Shell里 重启MySQL 8.4实例

前一段时间看到MySQL官方视频的Oracle工程师在mysql shell里面重启mysql实例&#xff0c;感觉这个操作很方便&#xff0c;所以来试试&#xff0c;下面为该工程师的操作截图 1.MySQL Shell 通过root用户连上mysql&#xff0c;shutdown mysql实例 [rootmysql8_3 bin]# mysqlshMy…

FANUC机器人GI与GO位置数据传输设置

FANUC机器人GI与GO位置数据传输设置&#xff08;整数小数分开发&#xff09; 一、概述 在 Fanuc 机器人应用中&#xff0c;如果 IO 点位足够&#xff0c;可以利用机器人 IO 传输位置数据及偏移位置数据等。 二、操作步骤 1、确认通讯软件安装 首先确认机器人控制柜已经安装…

LeetCode 24 两两交换链表中的节点

​给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1…

低代码平台开发手机USB-HID调试助手

项目介绍 USB-HID调试助手是一种专门用于调试和测试USB-HID设备的软件工具。USB-HID设备是一类通过USB接口与计算机通信的设备&#xff0c;常见的HID设备包括键盘、鼠标、游戏控制器、以及一些专用的工业控制设备等。 主要功能包括&#xff1a; 数据监控&#xff1a;实时监控和…

亚组风险比分析与可视化

1. 结果解读 1.1 风险比概述 1.1.1 风险比基本概念 风险比(Hazard Ratio)用于衡量治疗组与对照组事件发生的风险差异。 风险比为1,表示两组风险相同;小于1,治疗组风险低;大于1,治疗组风险高。 1.1.2 性别亚组分析 A性风险比小于1,表明治疗对A性有积极效果,风险降低。…

【博客系统】博客系统第一弹:博客系统项目配置、MyBatis-Plus 实现 Mapper 接口、处理项目公共模块:统一返回结果、统一异常处理

案例综合练习 - 博客系统 本节目标 从 0 到 1 完成博客系统后端项目的开发。 前言 通过前面课程的学习&#xff0c;我们掌握了 Spring 框架和 MyBatis 的基本使用&#xff0c;并完成了图书管理系统的常规功能开发。接下来我们系统地从 0 到 1 完成一个项目的开发。 项目介绍 …

基于OpenMV+STM32+OLED与YOLOv11+PaddleOCR的嵌入式车牌识别系统开发笔记

基于OpenMV、STM32与OLED的嵌入式车牌识别系统开发笔记 基于OpenMV、STM32与OLED的嵌入式车牌识别系统开发笔记系统架构全景 一、实物演示二、OpenMV端设计要点1. 硬件配置优化2. 智能帧率控制算法3. 数据传输协议设计 三、PyTorch后端核心实现&#xff1a;YOLOv11与PaddleOCR的…

w~嵌入式C语言~合集4

我自己的原文哦~ https://blog.51cto.com/whaosoft/13870376 一、STM32怎么选型 什么是 STM32 STM32&#xff0c;从字面上来理解&#xff0c;ST是意法半导体&#xff0c;M是Microelectronics的缩写&#xff0c;32表示32位&#xff0c;合起来理解&#xff0c;STM32就是指S…

K8S安全认证

一。用户认证的基本框架 在K8S集群中&#xff0c;客户端通常有两类&#xff1a; 1.User Account&#xff1a;一般独立于K8S之外的其他服务管理的用过户账号 2.Service Account&#xff1a;K8S管理的账号&#xff0c;用于为Pod中的服务进程在访问K8S提供身份标识 ApiServer是…

mybatis-plus里的com.baomidou.mybatisplus.core.override.MybatisMapperProxy 类的详细解析

以下是 com.baomidou.mybatisplus.core.override.MybatisMapperProxy 类的详细解析&#xff1a; 1. 类的作用 MybatisMapperProxy 是 MyBatis-Plus 框架中用于实现 Mapper 接口动态代理的核心类。它继承自 MyBatis 的 MapperProxy&#xff0c;并扩展了以下功能&#xff1a; …