基于SpringBoot实现文件的上传下载

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 文件上传下载一直都是一个系统最常用也是最基本的功能点,刚好最近公司的项目上有用到这个功能,于是自己就用SpringBoot也写了一个简化的版本,已实现文件的上传和下载功能。

网络异常,图片无法展示
|


听说微信搜索《Java鱼仔》会变更强哦!


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看哦


(一)概述



文件上传下载一直都是一个系统最常用也是最基本的功能点,刚好最近公司的项目上有用到这个功能,于是自己就用SpringBoot也写了一个简化的版本,已实现文件的上传和下载功能。


(二)创建项目



首先创建一个SpringBoot的项目,接着引入相关的依赖,因为涉及到数据库的操作,所以依赖会比较多一些。


2.1 依赖引入


<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.3</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>


2.2 接口通用返回类编写


编写一个接口的通用返回体,这个在之前的博客中我专门写过,现在就直接拿来用了:


publicenumResponseCode {
// 系统模块SUCCESS(0, "操作成功"),
ERROR(1, "操作失败"),
SERVER_ERROR(500, "服务器异常"),
// 通用模块 1xxxxILLEGAL_ARGUMENT(10000, "参数不合法"),
REPETITIVE_OPERATION(10001, "请勿重复操作"),
ACCESS_LIMIT(10002, "请求太频繁, 请稍后再试"),
MAIL_SEND_SUCCESS(10003, "邮件发送成功"),
// 用户模块 2xxxxNEED_LOGIN(20001, "登录失效"),
USERNAME_OR_PASSWORD_EMPTY(20002, "用户名或密码不能为空"),
USERNAME_OR_PASSWORD_WRONG(20003, "用户名或密码错误"),
USER_NOT_EXISTS(20004, "用户不存在"),
WRONG_PASSWORD(20005, "密码错误"),
// 文件模块 3xxxxFILE_EMPTY(30001,"文件不能空"),
FILE_NAME_EMPTY(30002,"文件名称不能为空"),
FILE_MAX_SIZE(30003,"文件大小超出"),
    ;
ResponseCode(Integercode, Stringmsg) {
this.code=code;
this.msg=msg;
    }
privateIntegercode;
privateStringmsg;
publicIntegergetCode() {
returncode;
    }
publicvoidsetCode(Integercode) {
this.code=code;
    }
publicStringgetMsg() {
returnmsg;
    }
publicvoidsetMsg(Stringmsg) {
this.msg=msg;
    }
}


返回体:


@Data@AllArgsConstructor@NoArgsConstructorpublicclassResult {
privateintcode;
privateStringmessage;
privateObjectdata;
}


2.3 配置一下解决跨域问题的配置类


在SpringBoot中有多种解决跨域的方法,这里选择其中一种


publicclassWebMvcConfigimplementsWebMvcConfigurer {
@OverridepublicvoidaddCorsMappings(CorsRegistryregistry) {
registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
                .maxAge(3600)
                .allowCredentials(true);
    }
}


到这里为止,基本的项目配置就算结束了,接下来就是功能的实现了。


(三)实现文件上传下载



3.1 创建表


首先创建一张表来记录文件的路径、名称、后缀等信息:


CREATETABLE`file` (
`id`int(11) NOTNULLAUTO_INCREMENT,
`filePath`varchar(255) DEFAULTNULL,
`fileName`varchar(255) DEFAULTNULL,
`fileSuffix`varchar(255) DEFAULTNULL,
PRIMARYKEY (`id`)
) ENGINE=InnoDBAUTO_INCREMENT=4DEFAULTCHARSET=utf8;


3.2 编写实体类


写一个文件对象,和数据库中的字段相对应:


@Data@AllArgsConstructor@NoArgsConstructor@Getter@Setter@EqualsAndHashCodepublicclassFilesimplementsSerializable {
privatestaticfinallongserialVersionUID=1L;
/*** 文件存储路径*/privateStringfilePath;
/*** 文件名称*/privateStringfileName;
/*** 文件后缀名*/privateStringfileSuffix;
}


3.3 配置application.properties


在配置文件中将服务端口,数据库连接方式以及文件的保存路径配置一下:


server.port=8080spring.datasource.url=jdbc:mysql://localhost:3306/test7?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8spring.datasource.username=rootspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis.mapper-locations=classpath:mapper/*.xmlfile.save-path=E:/temp/files


3.4 编写Controller


新建一个类叫FileController,用来写接口,文件上传下载接口的代码已经给了注释,Spring中提供了一个MultipartFile类,用来接收前台传过来的文件,这里直接使用即可。


@RestController@RequestMapping("/api")
publicclassFileController {
@AutowiredprivateFileServicefileService;
@RequestMapping(value="/upload",method=RequestMethod.POST)
publicResultupLoadFiles(MultipartFilemultipartFile){
if (multipartFile.isEmpty()){
returnnewResult(ResponseCode.FILE_EMPTY.getCode(),ResponseCode.FILE_EMPTY.getMsg(),null);
        }
returnfileService.upLoadFiles(multipartFile);
    }
@RequestMapping(value="/download/{id}",method=RequestMethod.GET)
publicvoiddownloadFiles(@PathVariable("id") Stringid, HttpServletRequestrequest, HttpServletResponseresponse){
OutputStreamoutputStream=null;
InputStreaminputStream=null;
BufferedInputStreambufferedInputStream=null;
byte[] bytes=newbyte[1024];
Filesfiles=fileService.getFileById(id);
StringfileName=files.getFileName();
// 获取输出流try {
response.setHeader("Content-Disposition", "attachment;filename="+newString(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1));
response.setContentType("application/force-download");
inputStream=fileService.getFileInputStream(files);
bufferedInputStream=newBufferedInputStream(inputStream);
outputStream=response.getOutputStream();
inti=bufferedInputStream.read(bytes);
while (i!=-1){
outputStream.write(bytes,0,i);
i=bufferedInputStream.read(bytes);
            }
        } catch (IOExceptione) {
e.printStackTrace();
        }finally {
try {
if (inputStream!=null){
inputStream.close();
                }
if (outputStream!=null){
outputStream.close();
                }
if (bufferedInputStream!=null){
bufferedInputStream.close();
                }
            } catch (IOExceptione) {
e.printStackTrace();
            }
        }
    }
}


所有的业务都写在service中,因此需要有fileService接口以及fileServiceImpl实现类:


publicinterfaceFileService {
/*** 文件上传接口* @param file* @return*/ResultupLoadFiles(MultipartFilefile);
/*** 根据id获取文件* @param id* @return*/FilesgetFileById(Stringid);
/*** 根据id获取数据流* @param files* @return*/InputStreamgetFileInputStream(Filesfiles);
}


fileServiceImpl实现类:


@ServicepublicclassFileServiceImplimplementsFileService {
@Value("${file.save-path}")
privateStringsavePath;
@AutowiredprivateFileMapperfileMapper;
@OverridepublicResultupLoadFiles(MultipartFilefile) {
//设置支持最大上传的文件,这里是1024*1024*2=2MlongMAX_SIZE=2097152L;
//获取要上传文件的名称StringfileName=file.getOriginalFilename();
//如果名称为空,返回一个文件名为空的错误if (StringUtils.isEmpty(fileName)){
returnnewResult(ResponseCode.FILE_NAME_EMPTY.getCode(),ResponseCode.FILE_NAME_EMPTY.getMsg(),null);
        }
//如果文件超过最大值,返回超出可上传最大值的错误if (file.getSize()>MAX_SIZE){
returnnewResult(ResponseCode.FILE_MAX_SIZE.getCode(),ResponseCode.FILE_MAX_SIZE.getMsg(),null);
        }
//获取到后缀名StringsuffixName=fileName.contains(".") ?fileName.substring(fileName.lastIndexOf(".")) : null;
//文件的保存重新按照时间戳命名StringnewName=System.currentTimeMillis() +suffixName;
FilenewFile=newFile(savePath,newName);
if (!newFile.getParentFile().exists()){
newFile.getParentFile().mkdirs();
        }
try {
//文件写入file.transferTo(newFile);
        } catch (IOExceptione) {
e.printStackTrace();
        }
//将这些文件的信息写入到数据库中Filesfiles=newFiles(newFile.getPath(),fileName,suffixName);
fileMapper.insertFile(files);
returnnewResult(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),"数据上传成功");
    }
//根据id获取文件信息@OverridepublicFilesgetFileById(Stringid) {
Filesfiles=fileMapper.selectFileById(id);
returnfiles;
    }
//将文件转化为InputStream@OverridepublicInputStreamgetFileInputStream(Filesfiles) {
Filefile=newFile(files.getFilePath());
try {
returnnewFileInputStream(file);
        } catch (FileNotFoundExceptione) {
e.printStackTrace();
        }
returnnull;
    }
}


3.5 对数据库的操作


需要将数据写入到数据库中,这里用到的是mybatis,新建一个FileMapper接口:


@Mapper@RepositorypublicinterfaceFileMapper {
/*** 将数据信息插入到数据库* @param files*/voidinsertFile(Filesfiles);
/*** 根据id获取文件* @param id* @return*/FilesselectFileById(Stringid);
}


编写对应的xml文件


<?xmlversion="1.0" encoding="UTF8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.javayz.fileuploadanddownload.mapper.FileMapper"><insertid="insertFile"parameterType="com.javayz.fileuploadanddownload.entity.Files">        insert into file(filepath,filename,filesuffix) values(#{filePath},#{fileName},#{fileSuffix});
</insert><selectid="selectFileById"parameterType="string"resultType="com.javayz.fileuploadanddownload.entity.Files">        select * from file where id=#{id};
</select></mapper>


代码已上传至github,欢迎自取:github


(四)测试



将项目运行起来,首先测试文件上传,通过postman直接上传一个文件


网络异常,图片无法展示
|


点击send后得到操作成功的返回值,我们可以在自己设置的路径下看到这个文件,同时在数据库中也存在该文件的信息:


网络异常,图片无法展示
|


接下来测试文件下载,因为是get请求,直接在浏览器中访问:


http://localhost:8080/api/download/4即可调用下载。



相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
6月前
|
XML Java Maven
springboot-多环境配置文件
本文介绍了如何创建开发和生产环境的配置文件,并在IDEA和Maven中进行配置。开发环境中,通过设置profile为`dev`来指定配置文件;生产环境中,使用Maven命令参数`-Pprod`打包并指定配置文件。公共配置可放在`application.yml`中统一管理。日志配置需确保`logback-spring.xml`中的profile正确,以保证日志正常输出。
341 4
springboot-多环境配置文件
|
5月前
|
XML 前端开发 Java
SpringBoot实现文件上传下载功能
本文介绍了如何使用SpringBoot实现文件上传与下载功能,涵盖配置和代码实现。包括Maven依赖配置(如`spring-boot-starter-web`和`spring-boot-starter-thymeleaf`)、前端HTML页面设计、WebConfig路径映射配置、YAML文件路径设置,以及核心的文件上传(通过`MultipartFile`处理)和下载(利用`ResponseEntity`返回文件流)功能的Java代码实现。文章由Colorful_WP撰写,内容详实,适合开发者学习参考。
527 0
|
7月前
|
存储 前端开发 Java
Springboot静态资源映射及文件映射
在Spring Boot项目中,为了解决前端访问后端存储的图片问题,起初尝试通过静态资源映射实现,但发现这种方式仅能访问打包时已存在的文件。对于动态上传的图片(如头像),需采用资源映射配置,将特定路径映射到服务器上的文件夹,确保新上传的图片能即时访问。例如,通过`addResourceHandler(&quot;/img/**&quot;).addResourceLocations(&quot;file:E:\\myProject\\forum_server\\&quot;)`配置,使前端可通过URL直接访问图片。
418 0
Springboot静态资源映射及文件映射
|
6月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
10月前
|
Java 应用服务中间件
SpringBoot获取项目文件的绝对路径和相对路径
SpringBoot获取项目文件的绝对路径和相对路径
552 1
SpringBoot获取项目文件的绝对路径和相对路径
|
11月前
|
XML Java Kotlin
springboot + minio + kkfile实现文件预览
本文介绍了如何在容器中安装和启动kkfileviewer,并通过Spring Boot集成MinIO实现文件上传与预览功能。首先,通过下载kkfileviewer源码并构建Docker镜像来部署文件预览服务。接着,在Spring Boot项目中添加MinIO依赖,配置MinIO客户端,并实现文件上传与获取预览链接的接口。最后,通过测试验证文件上传和预览功能的正确性。
971 4
springboot + minio + kkfile实现文件预览
|
10月前
|
网络协议 Java
springboot配置hosts文件
springboot配置hosts文件
157 11
|
10月前
|
前端开发 Java easyexcel
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
SpringBoot操作Excel实现单文件上传、多文件上传、下载、读取内容等功能
699 8
|
10月前
|
存储 前端开发 JavaScript
|
10月前
|
存储 Java API