文件上传和下载在项目中经常用到,这里主要学习SpringBoot完成单个文件上传/下载,批量文件上传的场景应用。结合mysql数据库、jpa数据层操作、thymeleaf页面模板。

一、准备

添加maven依赖

<!--springboot核心-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
​
<!--springboot测试-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
​
<!--thymeleaf前端模板-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
​
<!--springboot-web-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
​
<!--springboot热部署-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope>
</dependency>
​
<!--jpa-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
​
<!--lombok-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional>
</dependency>
​
<!--mysql驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

配置文件application.yml

server:port: 8081tomcat:max-swallow-size: 1MB
spring:servlet:multipart:# 默认支持文件上传enabled: true# 最大支持文件大小max-file-size: 50MB# 最大支持请求大小max-request-size: 100MB# 文件支持写入磁盘file-size-threshold: 0# 上传文件的临时目录location: /testdatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=trueusername: rootpassword: rootjpa:# 数据库类型database: mysql#打印SQLshow-sql: truehibernate:ddl-auto: update  #第一次启动创建表,之后修改为updatethymeleaf:# 是否启用enabled: true# 模板编码encoding: UTF-8# 模板模式mode: HTML5# 模板存放路径prefix: classpath:/templates/# 模板后缀suffix: .html# 启用缓存,建议生产开启cache: false# 校验模板是否存在check-template-location: true# Content-type值servlet:content-type: text/html# 加配置静态资源resources:static-locations: classpath:/
​
niaobulashi:file:path: D:workspacejavaProjectspring-boot-learningspring-boot-22-updownloaddocextension: .gif,.jpeg,.png,.jpg,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.rar,.tif

最下面是自定义的配置属性,定义了文件存放路径和上传文件允许的后缀名称。

需要注意的是:niaobulashi.file.path,为你磁盘上的目录,根据你实际的目录修改

数据库表sys_file_info

SET FOREIGN_KEY_CHECKS=0;
​
-- ----------------------------
-- Table structure for `sys_file_info`
-- ----------------------------
DROP TABLE IF EXISTS `sys_file_info`;
CREATE TABLE `sys_file_info` (`file_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文件id',`file_name` varchar(50) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件名称',`file_path` varchar(255) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件路径',`file_size` varchar(100) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件大小',PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文件信息表';

二、代码实现

结构目录

页面file.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<p>1、单文件上传</p>
<form action="upload" method="POST" enctype="multipart/form-data">文件:<input type="file" name="file"/><input type="submit"/>
</form>
<hr/>
<p>2、文件下载</p>
<form action="download" method="POST" enctype="multipart/form-data">文件ID:<input type="text" name="fileId"/><input type="submit" value="下载文件"/>
</form>
<hr/>
<p>3、多文件上传</p>
<form action="batchUpload" method="POST" enctype="multipart/form-data">一次选择多个文件的多文件上传:<input type="file" name="files" multiple><input type="submit"/>
</form>
</body>
</html>

统一返回ResponseCode

@Data
@AllArgsConstructor
public class ResponseCode extends HashMap<String, Object> {​private static final long serialVersionUID = 1L;
​public static final String CODE_TAG = "code";
​public static final String MSG_TAG = "msg";
​public static final String DATA_TAG = "data";
​/*** 状态类型*/public enum Type{/** 成功 */SUCCESS(100),/** 警告 */WARN(200),/** 错误 */ERROR(300);private final int value;
​Type(int value){this.value = value;}
​public int value(){return this.value;}}
​/** 状态类型 */private Type type;
​/** 状态码 */private int code;
​/** 返回内容 */private String msg;
​/** 数据对象 */private Object data;
​
​/*** 初始化一个新创建的 AjaxResult 对象** @param type 状态类型* @param msg 返回内容*/public ResponseCode(Type type, String msg){super.put(CODE_TAG, type.value);super.put(MSG_TAG, msg);}
​/*** 初始化一个新创建的 AjaxResult 对象** @param type 状态类型* @param msg 返回内容* @param data 数据对象*/public ResponseCode(Type type, String msg, Object data){super.put(CODE_TAG, type.value);super.put(MSG_TAG, msg);if (data !=null){super.put(DATA_TAG, data);}}
​/*** 返回成功消息** @return 成功消息*/public static ResponseCode success(){return ResponseCode.success("操作成功");}
​/*** 返回成功数据** @return 成功消息*/public static ResponseCode success(Object data){return ResponseCode.success("操作成功", data);}
​/*** 返回成功消息** @param msg 返回内容* @return 成功消息*/public static ResponseCode success(String msg){return ResponseCode.success(msg, null);}
​/*** 返回成功消息** @param msg 返回内容* @param data 数据对象* @return 成功消息*/public static ResponseCode success(String msg, Object data) {return new ResponseCode(Type.SUCCESS, msg, data);}
​/*** 返回警告消息** @param msg 返回内容* @return 警告消息*/public static ResponseCode warn(String msg){return ResponseCode.warn(msg, null);}
​/*** 返回警告消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static ResponseCode warn(String msg, Object data) {return new ResponseCode(Type.WARN, msg, data);}
​/*** 返回错误消息** @return*/public static ResponseCode error() {return ResponseCode.error("操作失败");}
​/*** 返回错误消息** @param msg 返回内容* @return 警告消息*/public static ResponseCode error(String msg) {return ResponseCode.error(msg, null);}
​/*** 返回错误消息** @param msg 返回内容* @param data 数据对象* @return 警告消息*/public static ResponseCode error(String msg, Object data) {return new ResponseCode(Type.ERROR, msg, data);}
​
}

model实体类SysFileInfo

@Data
@Entity
@Table(name = "sys_file_info")
public class SysFileInfo implements Serializable {​@Id@GeneratedValueprivate Integer fileId;
​@Column(nullable = false)private String fileName;
​@Column(nullable = false)private String filePath;
​@Column(nullable = false)private Long fileSize;
}

读取配置文件信息

@Data
@Component
public class GlobalProperties {​/** 文件存放路径 */@Value("${niaobulashi.file.path}")private String serverPath;
​/** 文件扩展名 */@Value("${niaobulashi.file.extension}")private String extension;
​
}

dao层

public interface SysFileInfoDao extends JpaRepository<SysFileInfo, Integer> {​
}

Controller层

关系的地方来了,其中有三部分:单文件上传、下载、批量文件上传

头部分

@Controller
public class FileController {
​private final Logger logger = LoggerFactory.getLogger(this.getClass());
​/*** 默认大小 50M*/public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
​@Autowiredprivate SysFileInfoDao sysFileInfoDao;
​@Autowiredprivate GlobalProperties globalProperties;
​/*** 文件上传页面* @return*/@GetMapping("/")public String updatePage() {return "file";}///....具体逻辑在下方
}

单文件上传

/*** 单文件上传* @param file* @return*/
@PostMapping("/upload")
@ResponseBody
private ResponseCode upload(@RequestParam("file") MultipartFile file) throws Exception {// 获取文件在服务器上的存储位置String serverPath = globalProperties.getServerPath();
​// 获取允许上传的文件扩展名String extension = globalProperties.getExtension();
​File filePath = new File(serverPath);logger.info("文件保存的路径为:" + filePath);if (!filePath.exists() && !filePath.isDirectory()) {logger.info("目录不存在,则创建目录:" + filePath);filePath.mkdir();}
​// 判断文件是否为空if (file.isEmpty()) {return ResponseCode.error("文件为空");}//判断文件是否为空文件if (file.getSize() <= 0) {return ResponseCode.error("文件大小为空,上传失败");}
​// 判断文件大小不能大于50Mif (DEFAULT_MAX_SIZE != -1 && file.getSize() > DEFAULT_MAX_SIZE) {return ResponseCode.error("上传的文件不能大于50M");}
​// 获取文件名String fileName = file.getOriginalFilename();// 获取文件扩展名String fileExtension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
​// 判断文件扩展名是否正确if (!extension.contains(fileExtension)) {return ResponseCode.error("文件扩展名不正确");}
​SysFileInfo sysFileInfo = new SysFileInfo();// 重新生成的文件名String saveFileName = System.currentTimeMillis() + fileExtension;// 在指定目录下创建该文件File targetFile = new File(filePath, saveFileName);
​logger.info("将文件保存到指定目录");try {file.transferTo(targetFile);} catch (IOException e) {throw new Exception(e.getMessage());}
​// 保存数据sysFileInfo.setFileName(fileName);sysFileInfo.setFilePath(serverPath + "/" + saveFileName);sysFileInfo.setFileSize(file.getSize());
​logger.info("新增文件数据");// 新增文件数据sysFileInfoDao.save(sysFileInfo);return ResponseCode.success("上传成功");
}

下载

下载的逻辑,我在前端通过input输入框输入fileId,后台查询数据库来下载

正常情况下应该是列表,单选或者多选后下载文件的。

/*** 下载* @param fileId* @param request* @param response* @return*/
@PostMapping("/download")
@ResponseBody
public ResponseCode downloadFile(@RequestParam("fileId") Integer fileId, HttpServletRequest request, HttpServletResponse response) {logger.info("文件ID为:" + fileId);// 判断传入参数是否非空if (fileId == null) {return ResponseCode.error("请求参数不能为空");}// 根据fileId查询文件表Optional<SysFileInfo> sysFileInfo = sysFileInfoDao.findById(fileId);if (sysFileInfo.isEmpty()) {return ResponseCode.error("下载的文件不存在");}// 获取文件全路径File file = new File(sysFileInfo.get().getFilePath());String fileName = sysFileInfo.get().getFileName();// 判断是否存在磁盘中if (file.exists()) {// 设置强制下载不打开response.setContentType("application/force-download");// 设置文件名response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);byte[] buffer = new byte[1024];FileInputStream fis = null;BufferedInputStream bis = null;try {fis = new FileInputStream(file);bis = new BufferedInputStream(fis);OutputStream os = response.getOutputStream();int i = bis.read(buffer);while (i != -1) {os.write(buffer, 0, i);i = bis.read(buffer);}return ResponseCode.success("下载成功");} catch (Exception e) {e.printStackTrace();} finally {if (bis != null) {try {bis.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}} else {return ResponseCode.error("数据库查询存在,本地磁盘不存在文件");}return ResponseCode.success("下载失败");
}

批量文件上传

/*** 批量文件上传* @param files* @return* @throws Exception*/
@PostMapping("/batchUpload")
@ResponseBody
public ResponseCode batchUpload(@RequestParam("files") MultipartFile[] files) throws Exception {if (files == null) {return ResponseCode.error("参数为空");}for (MultipartFile multipartFile : files) {upload(multipartFile);}return ResponseCode.success("批量上传成功");
}

至此项目完成,开始测试

三、测试

四、源码

emmm,私藏的可爱图片也给你们啦

源码地址:spring-boot-learning 欢迎star、fork,给作者一些鼓励

java批量上传文件_Spring Boot2(十四):单文件上传/下载,文件批量上传相关推荐

  1. Safari浏览器下载word文件,后缀多拼接了.html,导致打开下载文件乱码

    1.遇到的问题 谷歌和ie下载文件正常 Safari浏览器下载word文件,后缀多拼接了.html,导致打开下载文件乱码,下载的文件名称为test.doc.html,手动去掉多余的后缀.html即可正 ...

  2. springboot传入json和文件_Spring Boot之 Controller 接收参数和返回数据总结(包括上传、下载文件)...

    server: port: 8088 servlet: context-path: /sid spring: mvc: view: prefix: / suffix: .html /** * 返回界面 ...

  3. .vue文件_Spring Boot + Vue 前后端分离,两种文件上传方式总结!

    在Vue.js 中,如果网络请求使用 axios ,并且使用了 ElementUI 库,那么一般来说,文件上传有两种不同的实现方案: 通过 Ajax 实现文件上传 通过 ElementUI 里边的 U ...

  4. linux禁止客户端上传文件_Linux下Shell脚本实现FTP自动上传和下载文件

    概述 之前测试写的一个脚本,主要是为了实现FTP自动上传和下载文件.大家可以参考下: 基础环境配置 [root@pxzxdm01 ~]# useradd -d /home/ftp1 ftp1 [roo ...

  5. Android之解决PC端上传http表单格式文件手机解析文件名乱码问题和PC浏览器下载文件的文件名显示乱码问题

    1 问题 问题1. 手机写socket作为服务器,PC浏览器上传http表单格式文件,然后手机端解析携带中文的文件名我解析是乱码. 问题2. 手机写了socket作为服务器,PC浏览器下载文件,但是浏 ...

  6. linux上传文件命令ftp put,Linux ftp 命令行中下载文件get与上传文件put的命令应用详解...

    介绍:从本地以用户anok登录的机器192.168.0.16上通过ftp远程登录到192.168.0.6的ftp服务器上,登录用户名是peo.以下为使用该连接做的实验. 查看远程ftp服务器上用户pe ...

  7. linux上传文件put,详解Linux ftp 命令行中下载文件get与上传文件put的操作方法

    尽管现在有许多好的FTP应用程序,但服务器命令行ftp命令的应用程序仍然很多,下面就让电脑乐园小编带你一起来学习详解Linux ftp 命令行中下载文件get与上传文件put的操作方法. 介绍:从本地 ...

  8. 命令行curl上传文件_命令行基础知识:使用cURL下载文件

    命令行curl上传文件 Client URL, or simple cURL is a library and command-line utility for transferring data b ...

  9. SpringBatch 写xml文件(StaxEventItemWriter)用法(十四)

    文章目录 一.pom文件引入需要读取xml文件jar包 二.抽取写xml文件公共writer 三.processor 四.配置写xml文件job 五.执行job 前言:在一些业务场景中,可能需要读取x ...

最新文章

  1. Android跨平台编译 —— BOOST
  2. Theme,skin-----asp.net2.0 new technolog
  3. 面到阿里月薪 27k 数据岗,很难?
  4. jMeter 里如何使用 properties
  5. ipython安装成功却无法运营_pyspider显示安装成功但仍无法运行
  6. matlab中的[~,m]=size(coord)是什么意思
  7. MFC开发IM-第十篇、MFC改变static text颜色
  8. java开启一个线程_【jdk源码分析】java多线程开启的三种方式
  9. mysql查询每日/某时间段/当日新增用户人数
  10. Windows访问Linux下的共享目录的配置方法(user安全级别)
  11. Keras深度学习实战(2)——使用Keras构建神经网络
  12. 后妈茶话会_歌词(Tough Love)
  13. 经营生鲜便利店的超级产品战略,盘点那些靠卖菜抢占社区的便利店
  14. 使用Composer部署laravel框架
  15. 计算机b类核心期刊有哪些,cssci、A类、B类、C类、核心期刊都是什么等级的期刊?...
  16. Win7快速启动栏设置及防止消失方法
  17. 【LEETCODE】【鱼缸难题】
  18. Android LocalServices解耦妙用: system_server进程中各个服务之间的连通器LocalServices
  19. 让Meebo自动变换背景的客户端脚本
  20. 谈谈Gameplay,以及UE4的Gameplay框架

热门文章

  1. 统计学常见分布、概念
  2. android pm命令用法
  3. Linux 的简单钩子
  4. tensorflow之add_to_collection
  5. 防火墙审计策略和应用场景介绍(USG6307E)
  6. 监控三剑客<cacti、nagios、zabbix>
  7. 进阶03 System、StringBuilder类
  8. Android中GsonFormat的安装及使用
  9. 关于zynq lwip link speed for phy address 1:0的问题
  10. andriod studio获取root_怎样获得root权限