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

Java后端如何进行文件上传和下载 —— 本地版

简介: 本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。

大体思路

1、文件上传

文件上传保存到本地,我们要关注的是文件怎样接收,怎样保存,保存在哪?

首先,既然是文件,就要有对应的文件保存地址,或者说文件保存路径和文件保存目录都可以,如下面这个代码,我们定义一个字符串用来表示文件保存地址。

System.getProperty("user.dir") 表示当前后端项目的路径,是固定的写法。它会自动识别当前项目所在的根路径,每个人的可能都不一样

File.separator 表示分隔符,也就是斜杠 /

files表示之后所有的文件都存储在 files 文件包下

比如此处我的 ROOT_PATH(文件路径) 是 D:\code_github\Dream_java\java_chatroom\files

首先,此处每个人的路径肯定都不相同,不要疑问为什么和我的不一样,因为咱项目所在位置就不一样

其次,你也可以指定其它的路径,这都是开放性的选择

private static final String ROOT_PATH = System.getProperty("user.dir") + File.separator + "files";

我们写一个接口,路径随意,比如我这里的 /uploadceshi

@PostMapping("/uploadceshi")

然后呢,我们写对应的方法,方法要有参数,既然是文件,我们就使用 MultipartFile 类型来进行接收,后续也可以使用它的很多内置函数来进行文件的处理

public String uploadCeshi(MultipartFile file){}

然后,这样一个基础的接口就写好了,而且已经能接收前端传来的文件了,当前端上传文件后,文件就保存成了我们的 file 参数,接下来就可以对文件进行处理了。

首先,我们要获取文件的原始名称来进行存储,并取得文件的主名称和后缀以供后续使用

String originalFilename = file.getOriginalFilename();  // 文件的原始名称    aaa.png
log.info("文件的原始名称:{}", originalFilename);
String mainName = FileUtil.mainName(originalFilename);  // 文件的主名称    aaa
log.info("文件的原始主名称:{}", mainName);
String extName = FileUtil.extName(originalFilename);  // 文件的扩展名(后缀)    .png
log.info("文件的原始后缀:{}", extName);

log.info 是日志打印的代码,类似于 System.out.println() ,如果 log.info 看不懂的话换成 System.out.println() 也是可以的

还记得我们开始定义的保存文件的父级目录么,也就是 ROOT_PATH,现在我们要保存文件了,既然要保存,我们需要判断这个父级目录是否存在,如果不存在,我们要先创建这个 “父级目录”

// 如果当前文件的父级目录不存在,就创建
if(!FileUtil.exist(ROOT_PATH)){FileUtil.mkdir(ROOT_PATH);    // 如果当前文件的父级目录不存在,就创建
}

注意 FileUtil 不要导错包了,此处我使用的是 hutool 的

如果不知道 hutool 是啥,在maven仓库里搜下对应的依赖,导入到 pom.xml 里就可以了

hutool 是个知名的工具包,类似于 lombok

未成功先言败,我们继续判断特殊情况,比如当前上传的文件已经存在了,那么这个时候我就要重命名一个文件

// 如果当前上传的文件已经存在了,那么这个时候我就要重命名一个文件
if(FileUtil.exist(ROOT_PATH + File.separator + originalFilename)){originalFilename = System.currentTimeMillis() + "-" + mainName + "." + extName;log.info("文件已经存在,重命名后的文件名:{}", originalFilename);
}

特殊情况都处理完了,我们进行文件的存储

File saveFile = new File(ROOT_PATH + File.separator + originalFilename);   // 要保存的文件地址/目录
file.transferTo(saveFile);  // 存储文件到本地的磁盘里面去

最后,我们返回给前端一个URL,也就是后续我们的下载接口地址

// 返回文件的链接,这个链接就是文件的下载地址,这个下载地址就是我的后台提供出来的
String url = "http://" + ip + ":" + port + "/file/download?fileName=" + originalFilename;
log.info("文件的下载地址:{}", url);
return url;

ip和port换成你对应的ip和端口号即可,拼接成字符串,比如我这里返回的url:

http://localhost:8080/file/download?fileName=消息队列设计.pdf

完整上传接口代码如下:

ip、port 以及 ROOT_PATH 是我在类中,这个方法外定义的变量,所以没在下面这段代码里

@PostMapping("/uploadceshi")public String uploadCeshi(MultipartFile file) throws IOException {String originalFilename = file.getOriginalFilename();  // 文件的原始名称    aaa.pnglog.info("文件的原始名称:{}", originalFilename);String mainName = FileUtil.mainName(originalFilename);  // 文件的主名称    aaalog.info("文件的原始主名称:{}", mainName);String extName = FileUtil.extName(originalFilename);  // 文件的扩展名(后缀)    .pnglog.info("文件的原始后缀:{}", extName);System.out.println();// 如果当前文件的父级目录不存在,就创建if(!FileUtil.exist(ROOT_PATH)){FileUtil.mkdir(ROOT_PATH);    // 如果当前文件的父级目录不存在,就创建}// 如果当前上传的文件已经存在了,那么这个时候我就要重命名一个文件if(FileUtil.exist(ROOT_PATH + File.separator + originalFilename)){originalFilename = System.currentTimeMillis() + "-" + mainName + "." + extName;log.info("文件已经存在,重命名后的文件名:{}", originalFilename);}File saveFile = new File(ROOT_PATH + File.separator + originalFilename);   // 要保存的文件地址/目录file.transferTo(saveFile);  // 存储文件到本地的磁盘里面去// 返回文件的链接,这个链接就是文件的下载地址,这个下载地址就是我的后台提供出来的
//        String url = "http://" + ip + ":" + port + "/file/download/" + originalFilename;String url = "http://" + ip + ":" + port + "/file/download?fileName=" + originalFilename;log.info("文件的下载地址:{}", url);return url;}

2、文件下载

这个接口代码量少,逻辑清晰,我直接将代码全部放在下面,然后一下子讲述完

这个接口的访问地址就是上传接口返回的url

下载接口有两个参数,fileName接收想要下载的文件名

response.addHeader 等会再讲,先简单讲述下作用,使用第一个 response.addHeader 时,访问url文件直接下载,无法预览,使用第二个 response.addHeader 时,访问url文件如果可以预览,则先预览,不可以,会进行下载

先取得完整的文件路径名,如果路径不存在,直接返回空,存在则以字节流数组的方式返回前端

有人可能会疑问,这里我写的返回类型不是 void 么?怎么还可以返回数据给前端呢。这个简单理解为特殊情况吧,而且文件IO本就相对于文本数据的操作有极大的不同

    @GetMapping("/download")public void download(String fileName, HttpServletResponse response) throws IOException {
//        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件下载// 默认格式就是预览,浏览器会根据格式进行判断,如果可以就预览,不可以就下载
//        response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件预览String filePath = ROOT_PATH + File.separator + fileName;if(!FileUtil.exist(filePath)){return;}byte[] bytes = FileUtil.readBytes(filePath);ServletOutputStream outputStream = response.getOutputStream();outputStream.write(bytes);    // 数组是一个字节数组,也就是文件的字节流数组outputStream.flush();outputStream.close();}

特殊讲解 —— 必看

1、文件预览/下载

//  response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件下载
// 默认格式就是预览,浏览器会根据格式进行判断,如果可以就预览,不可以就下载
//  response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件预览

注意这两行代码

  • 使用第一行代码就是文件下载
  • 使用第二行代码就是文件预览,若无法预览则下载(像图片、PDF可以预览,应用软件包等无法1预览)

很多东西可能有疑问?为什么?

那么此处就要讲一下响应中的一个属性了,Content-Disposition,当这个属性默认是inline

  • 当它是 inline 时,浏览器会进行下载操作
  • 当它是 attachment 时,浏览器会进行下载操作

至于详细的就要剖析HTTP或HTTPS的请求和响应格式了,感兴趣的朋友可以自己去了解

2、文件上传/下载大小限制

# 设置上传文件的限制大小
spring:servlet:multipart:max-file-size: 30MBmax-request-size: 30MB

代码运行失败解决方法

1、包一定不要引错!!!比如 lombok 和 hutool

2、ip和端口号换成自己的,或者像我一样在yml里自己定义

3、文件可以预览或者下载,请详细阅读此篇博客目录中的 “特殊讲解 —— 必看”

4、文件过大无法上传或下载,请详细阅读此篇博客目录中的 “特殊讲解 —— 必看”

完整代码

注:hutool、lombok等自行导入,在maven仓库搜依赖即可(方式很多)

ip、port是我在yml里定义的,你直接换成你自己的ip和端口号即可(一定要换

package com.example.demo.controller;import cn.hutool.core.io.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;@RestController
@Slf4j
@RequestMapping("/file")
public class FileCeshiController {// 项目启动的ip地址@Value("${ip:localhost}")  // 给 ip 一个默认值,防止忘定义时报错String ip;// 项目启动的端口号@Value("${server.port}")String port;// System.getProperty("user.dir") 获取当前项目的根路径  此处为 D:\code_github\Dream_java\java_chatroom// File.separator 分隔符,即 \     (Windows 和 ios 通用)private static final String ROOT_PATH = System.getProperty("user.dir") + File.separator + "files";@PostMapping("/uploadceshi")public String uploadCeshi(MultipartFile file) throws IOException {String originalFilename = file.getOriginalFilename();  // 文件的原始名称    aaa.pnglog.info("文件的原始名称:{}", originalFilename);String mainName = FileUtil.mainName(originalFilename);  // 文件的主名称    aaalog.info("文件的原始主名称:{}", mainName);String extName = FileUtil.extName(originalFilename);  // 文件的扩展名(后缀)    .pnglog.info("文件的原始后缀:{}", extName);System.out.println();// 如果当前文件的父级目录不存在,就创建if(!FileUtil.exist(ROOT_PATH)){FileUtil.mkdir(ROOT_PATH);    // 如果当前文件的父级目录不存在,就创建}// 如果当前上传的文件已经存在了,那么这个时候我就要重命名一个文件if(FileUtil.exist(ROOT_PATH + File.separator + originalFilename)){originalFilename = System.currentTimeMillis() + "-" + mainName + "." + extName;log.info("文件已经存在,重命名后的文件名:{}", originalFilename);}File saveFile = new File(ROOT_PATH + File.separator + originalFilename);   // 要保存的文件地址/目录file.transferTo(saveFile);  // 存储文件到本地的磁盘里面去// 返回文件的链接,这个链接就是文件的下载地址,这个下载地址就是我的后台提供出来的String url = "http://" + ip + ":" + port + "/file/download?fileName=" + originalFilename;log.info("文件的下载地址:{}", url);return url;}@GetMapping("/download")public void download(String fileName, HttpServletResponse response) throws IOException {
//        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件下载// 默认格式就是预览,浏览器会根据格式进行判断,如果可以就预览,不可以就下载
//        response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(fileName, "UTF-8"));  // 附件预览String filePath = ROOT_PATH + File.separator + fileName;if(!FileUtil.exist(filePath)){return;}byte[] bytes = FileUtil.readBytes(filePath);ServletOutputStream outputStream = response.getOutputStream();outputStream.write(bytes);    // 数组是一个字节数组,也就是文件的字节流数组outputStream.flush();outputStream.close();}}

转载至:Java后端如何进行文件上传和下载 —— 本地版(文末配绝对能用的源码,超详细,超好用,一看就懂,博主在线解答) 文件如何预览和下载?(超简单教程)-阿里云开发者社区

相关文章:

Java后端如何进行文件上传和下载 —— 本地版

简介: 本文详细介绍了在Java后端进行文件上传和下载的实现方法,包括文件上传保存到本地的完整流程、文件下载的代码实现,以及如何处理文件预览、下载大小限制和运行失败的问题,并提供了完整的代码示例。 大体思路 1、文件上传 …...

json格式数据集转换成yolo的txt格式数据集

这个代码是参考了两个博客 我是感觉第一篇博客可能有问题,然后自己做了改进,如果我是错误的或者正确的,请各位评论区说一下,感谢 Json格式的数据集标签转化为有效的txt格式(data_coco)_train.json-CSDN博客 COCO(.j…...

什么是Three.js,有什么特点

什么是 Three.js? Three.js 是一个基于 WebGL 技术的 JavaScript 3D 库。它允许开发者在网页上创建和展示 3D 图形内容,而无需用户安装任何额外的插件或软件。Three.js 简化了 WebGL 的复杂性,使得即便是对图形编程不太熟悉的人也能快速上手…...

Linux笔记--基于OCRmyPDF将扫描件PDF转换为可搜索的PDF

1--官方仓库 https://github.com/ocrmypdf/OCRmyPDF 2--基本步骤 # 安装ocrmypdf库 sudo apt install ocrmypdf# 安装简体中文库 sudo apt-get install tesseract-ocr-chi-sim# 转换 # -l 表示使用的语言 # --force-ocr 防止出现以下错误:ERROR - PriorOcrFoundE…...

Unity 导出 Xcode 工程 修改 Podfile 文件

Unity 导出 Xcode 工程 修改 Podfile 文件 在 Editor 文件夹下新建 xxx.cs 脚本 实现静态方法 [PostProcessBuild]public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject){// Unity 导出 Xcode 工程自动调用这个方法 }using System.IO; using…...

UE5 slate BlankProgram独立程序系列

源码版Engine\Source\Programs\中copy BlankProgram文件夹,重命名为ASlateLearning,修改所有文件命名及内部名称。 ASlateLearning.Target.cs // Copyright Epic Games, Inc. All Rights Reserved.using UnrealBuildTool; using System.Collections.Ge…...

内存不足引发C++程序闪退崩溃问题的分析与总结

目录 1、内存不足一般出现在32位程序中 2、内存不足时会导致malloc或new申请内存失败 2.1、malloc申请内存失败,返回NULL 2.2、new申请内存失败,抛出异常 3、内存不足项目实战案例中相关细节与要点说明 3.1、内存不足导致malloc申请内存失败&#…...

C++ —— 以真我之名 如飞花般绚丽 - 智能指针

目录 1. RAII和智能指针的设计思路 2. C标准库智能指针的使用 2.1 auto_ptr 2.2 unique_ptr 2.3 简单模拟实现auto_ptr和unique_ptr的核心功能 2.4 shared_ptr 2.4.1 make_shared 2.5 weak_ptr 2.6 shared_ptr的缺陷:循环引用问题 3. shared_ptr 和 unique_…...

Linux中安装InfluxDB

什么是InfluxDB InfluxDB是一个开源的时间序列数据库,专为处理时间序列数据而设计。时间序列数据是指带有时间戳的数据点,例如传感器数据、应用程序日志、服务器指标等。InfluxDB 由 InfluxData 公司开发,广泛应用于物联网(IoT&am…...

nginx服务器实现上传文件功能_使用nginx-upload-module模块

目录 conf文件内容如下html文件内容如下上传文件功能展示 conf文件内容如下 #user nobody; worker_processes 1;error_log /usr/logs/error.log; #error_log /usr/logs/error.log notice; #error_log /usr/logs/error.log info;#pid /usr/logs/nginx.pid;events …...

ORB-SLAM2源码学习:Initializer.cc:Initializer::ComputeF21地图初始化——计算基础矩阵

前言 在平面场景我们通过求解单应矩阵H来求解位姿&#xff0c;但是我们在实际中常见的都是非平面场景&#xff0c; 此时需要用基础矩阵F求解位姿。 1.函数声明 cv::Mat Initializer::ComputeF21(const vector<cv::Point2f> &vP1, const vector<cv::Point2f>…...

C# 读取多条数据记录导出到 Word标签模板之图片输出改造

目录 应用需求 设计 范例运行环境 配置Office DCOM 实现代码 组件库引入 ​核心代码 调用示例 小结 应用需求 在我的文章《C# 读取多条数据记录导出到 Word 标签模板》里&#xff0c;讲述读取多条数据记录结合 WORD 标签模板输出文件的功能&#xff0c;原有输出图片的…...

NSSCTF web刷题

1 虽然找到了flag,但是我要怎么去改他的代码,让他直接输出flag呢? (好像是要得到他的json代码,这题不让看) 2 wllm应该就是他的密码,进入许可了 意思是服务器可以执行通过POST的请求方式传入参数为wllm的命令&#xff0c;那这就是典型的命令执行&#xff0c;当然&#xff0c…...

对象排序得到方式

java实现 list 排序的方式&#xff0c;有三种 ① 对象实现Comparable 接口&#xff0c;然后代码里直接调用Collections.sort(list) ②使用内部类Comparator ③使用stream.sort 代码如下 实现Comparable接口的实体类 Data public class Student implements Comparable<Stud…...

Day2 洛谷1035+1047+1085+1089+1150+1151

零基础洛谷刷题记录 Day1 2024.11.18 Day2 2024.11.25 文章目录 零基础洛谷刷题记录1035:题目描述1035&#xff1a;解答代码1035&#xff1a;学习成果1047&#xff1a;题目描述&#xff08;成功写出&#xff09;1047&#xff1a;解答代码1047&#xff1a;学习成果1085&#xf…...

Linux:进程间通信之进程池和日志

一、进程池的设计 因为每一次我们要进行进程间通信都需要fork&#xff0c;和操作系统做交互是存在很大成本的&#xff0c;所以我们是不是可以提前fork出几个进程&#xff0c;然后当我们想要使用的时候直接去给他们安排任务&#xff0c;这样就减少了系统调用的次数从而提高了内存…...

详细介绍HTTP与RPC:为什么有了HTTP,还需要RPC?

目录 一、HTTP 二、RPC 介绍 工作原理 核心功能 如何服务寻址 如何进行序列化和反序列化 如何网络传输 基于 TCP 协议的 RPC 调用 基于 HTTP 协议的 RPC 调用 实现方式 优点和缺点 使用场景 常见框架 示例 三、问题 问题一&#xff1a;是先有HTTP还是先有RPC&…...

Paddle Inference部署推理(十二)

十二&#xff1a;Paddle Inference推理 &#xff08;python&#xff09;API详解 15. PredictorPool 类 PredictorPool 对 Predictor 进行了简单的封装&#xff0c;通过传入 config 和 thread 的数目来完成初始化&#xff0c;在每个线程中&#xff0c;根据自己的线程 id 直接从…...

外观模式 (Facade Pattern)

外观模式 (Facade Pattern) 外观模式是一种 结构型设计模式&#xff0c;通过为子系统中的一组接口提供一个统一的高层接口&#xff0c;简化了子系统的使用&#xff0c;让复杂系统更易于访问。 原理 核心思想&#xff1a; 提供一个 统一的接口 来访问子系统中的多个接口&#…...

人工智能-深度学习-Torch框架-手动构建回归流程

from sklearn.datasets import make_regression import math import random import torch from sklearn.datasets import make_regression: 导入make_regression函数&#xff0c;用于生成回归数据集。 import math: 导入math模块&#xff0c;用于进行数学计算&#xff0c;例如…...

零基础玩转OpenClaw:星图Qwen3-32B镜像的10个入门级自动化案例

零基础玩转OpenClaw&#xff1a;星图Qwen3-32B镜像的10个入门级自动化案例 1. 为什么选择OpenClawQwen3-32B组合&#xff1f; 去年冬天&#xff0c;当我第一次听说OpenClaw这个开源自动化框架时&#xff0c;内心是既兴奋又忐忑的。兴奋的是终于有一个能在本地电脑上实现AI自动…...

【网络安全基础】计算机网络基础:从TCP/IP协议栈到网络攻击原理

前言在网络安全领域&#xff0c;不懂网络协议&#xff0c;就如同不懂解剖学的医生。无论是分析网络攻击流量、配置防火墙规则&#xff0c;还是进行内网渗透&#xff0c;都离不开对网络协议的深入理解。本文将系统梳理计算机网络的核心知识——从OSI七层模型到TCP/IP协议栈&…...

零知识证明终极指南:Awesome ZKP项目快速入门教程

零知识证明终极指南&#xff1a;Awesome ZKP项目快速入门教程 【免费下载链接】awesome-zero-knowledge-proofs A curated list of awesome things related to learning Zero-Knowledge Proofs (ZKP). 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-zero-knowledge-p…...

OpenClaw+GLM-4.7-Flash:自动化代码审查

OpenClawGLM-4.7-Flash&#xff1a;自动化代码审查 1. 为什么需要自动化代码审查 作为一个独立开发者&#xff0c;我经常面临一个尴尬局面&#xff1a;在深夜写完代码后直接提交&#xff0c;第二天醒来发现代码中存在明显的逻辑漏洞或风格问题。传统解决方案要么依赖昂贵的Sa…...

掌握小程序逆向工具:wxapkg解析与代码还原全流程指南

掌握小程序逆向工具&#xff1a;wxapkg解析与代码还原全流程指南 【免费下载链接】wxappUnpacker 项目地址: https://gitcode.com/gh_mirrors/wxappu/wxappUnpacker 当你需要逆向分析小程序包时&#xff0c;是否遇到过这些痛点&#xff1f;wxapkg文件无法直接查看内容、…...

AI时代的程序员应该如何就业突击找工作?编程语言该如何选择才不会被时代所淘汰?

AI时代的程序员应该如何就业突击找工作&#xff1f;编程语言该如何选择才不会被时代所淘汰&#xff1f; AI时代程序员就业突击与编程语言选择指南 一、就业突击策略 核心能力强化 算法与数据结构&#xff1a;掌握基础算法&#xff08;排序/搜索&#xff09;和高级结构&#x…...

供应链需求预测系统:Granite TimeSeries FlowState R1助力库存优化

供应链需求预测系统&#xff1a;Granite TimeSeries FlowState R1助力库存优化 每次大促过后&#xff0c;仓库里总是一片狼藉。畅销品早早断货&#xff0c;客服电话被打爆&#xff1b;而另一堆商品却纹丝不动&#xff0c;占满了宝贵的库位&#xff0c;资金就这么被“冻”在了货…...

基于django+vue的智慧物业来访预约报修管理系统

目录功能模块划分核心业务功能特色功能设计技术实现要点扩展性设计项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作功能模块划分 后台管理&#xff08;Django&#xff09; 用户权限管理&#xff1a;业主、物业管理员、维修人员…...

实战指南:如何为你的应用选择最优Cache替换算法(附性能对比)

实战指南&#xff1a;如何为你的应用选择最优Cache替换算法&#xff08;附性能对比&#xff09; 在构建高性能应用时&#xff0c;缓存系统的设计往往是决定整体性能的关键因素之一。想象一下&#xff0c;一个电商网站在大促期间&#xff0c;每秒需要处理数十万次商品详情查询&a…...

【配电网故障定位】基于改进粒子群算法的配电网故障定位研究附Matlab代码参考文献

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长毕业设计辅导、数学建模、数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和…...