java批量上传文件_Spring Boot2(十四):单文件上传/下载,文件批量上传
文件上传和下载在项目中经常用到,这里主要学习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(十四):单文件上传/下载,文件批量上传相关推荐
- Safari浏览器下载word文件,后缀多拼接了.html,导致打开下载文件乱码
1.遇到的问题 谷歌和ie下载文件正常 Safari浏览器下载word文件,后缀多拼接了.html,导致打开下载文件乱码,下载的文件名称为test.doc.html,手动去掉多余的后缀.html即可正 ...
- springboot传入json和文件_Spring Boot之 Controller 接收参数和返回数据总结(包括上传、下载文件)...
server: port: 8088 servlet: context-path: /sid spring: mvc: view: prefix: / suffix: .html /** * 返回界面 ...
- .vue文件_Spring Boot + Vue 前后端分离,两种文件上传方式总结!
在Vue.js 中,如果网络请求使用 axios ,并且使用了 ElementUI 库,那么一般来说,文件上传有两种不同的实现方案: 通过 Ajax 实现文件上传 通过 ElementUI 里边的 U ...
- linux禁止客户端上传文件_Linux下Shell脚本实现FTP自动上传和下载文件
概述 之前测试写的一个脚本,主要是为了实现FTP自动上传和下载文件.大家可以参考下: 基础环境配置 [root@pxzxdm01 ~]# useradd -d /home/ftp1 ftp1 [roo ...
- Android之解决PC端上传http表单格式文件手机解析文件名乱码问题和PC浏览器下载文件的文件名显示乱码问题
1 问题 问题1. 手机写socket作为服务器,PC浏览器上传http表单格式文件,然后手机端解析携带中文的文件名我解析是乱码. 问题2. 手机写了socket作为服务器,PC浏览器下载文件,但是浏 ...
- linux上传文件命令ftp put,Linux ftp 命令行中下载文件get与上传文件put的命令应用详解...
介绍:从本地以用户anok登录的机器192.168.0.16上通过ftp远程登录到192.168.0.6的ftp服务器上,登录用户名是peo.以下为使用该连接做的实验. 查看远程ftp服务器上用户pe ...
- linux上传文件put,详解Linux ftp 命令行中下载文件get与上传文件put的操作方法
尽管现在有许多好的FTP应用程序,但服务器命令行ftp命令的应用程序仍然很多,下面就让电脑乐园小编带你一起来学习详解Linux ftp 命令行中下载文件get与上传文件put的操作方法. 介绍:从本地 ...
- 命令行curl上传文件_命令行基础知识:使用cURL下载文件
命令行curl上传文件 Client URL, or simple cURL is a library and command-line utility for transferring data b ...
- SpringBatch 写xml文件(StaxEventItemWriter)用法(十四)
文章目录 一.pom文件引入需要读取xml文件jar包 二.抽取写xml文件公共writer 三.processor 四.配置写xml文件job 五.执行job 前言:在一些业务场景中,可能需要读取x ...
最新文章
- Android跨平台编译 —— BOOST
- Theme,skin-----asp.net2.0 new technolog
- 面到阿里月薪 27k 数据岗,很难?
- jMeter 里如何使用 properties
- ipython安装成功却无法运营_pyspider显示安装成功但仍无法运行
- matlab中的[~,m]=size(coord)是什么意思
- MFC开发IM-第十篇、MFC改变static text颜色
- java开启一个线程_【jdk源码分析】java多线程开启的三种方式
- mysql查询每日/某时间段/当日新增用户人数
- Windows访问Linux下的共享目录的配置方法(user安全级别)
- Keras深度学习实战(2)——使用Keras构建神经网络
- 后妈茶话会_歌词(Tough Love)
- 经营生鲜便利店的超级产品战略,盘点那些靠卖菜抢占社区的便利店
- 使用Composer部署laravel框架
- 计算机b类核心期刊有哪些,cssci、A类、B类、C类、核心期刊都是什么等级的期刊?...
- Win7快速启动栏设置及防止消失方法
- 【LEETCODE】【鱼缸难题】
- Android LocalServices解耦妙用: system_server进程中各个服务之间的连通器LocalServices
- 让Meebo自动变换背景的客户端脚本
- 谈谈Gameplay,以及UE4的Gameplay框架