写点什么

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

用户头像
Java鱼仔
关注
发布于: 2021 年 02 月 25 日

听说微信搜索《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 接口通用返回类编写

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


public enum ResponseCode {    // 系统模块    SUCCESS(0, "操作成功"),    ERROR(1, "操作失败"),    SERVER_ERROR(500, "服务器异常"),
// 通用模块 1xxxx ILLEGAL_ARGUMENT(10000, "参数不合法"), REPETITIVE_OPERATION(10001, "请勿重复操作"), ACCESS_LIMIT(10002, "请求太频繁, 请稍后再试"), MAIL_SEND_SUCCESS(10003, "邮件发送成功"),
// 用户模块 2xxxx NEED_LOGIN(20001, "登录失效"), USERNAME_OR_PASSWORD_EMPTY(20002, "用户名或密码不能为空"), USERNAME_OR_PASSWORD_WRONG(20003, "用户名或密码错误"), USER_NOT_EXISTS(20004, "用户不存在"), WRONG_PASSWORD(20005, "密码错误"),
// 文件模块 3xxxx FILE_EMPTY(30001,"文件不能空"), FILE_NAME_EMPTY(30002,"文件名称不能为空"), FILE_MAX_SIZE(30003,"文件大小超出"), ;
ResponseCode(Integer code, String msg) { this.code = code; this.msg = msg; } private Integer code; private String msg; public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; }}
复制代码


返回体:


@Data@AllArgsConstructor@NoArgsConstructorpublic class Result {    private int code;    private String message;    private Object data;}
复制代码


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

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


public class WebMvcConfig implements WebMvcConfigurer {    @Override    public void addCorsMappings(CorsRegistry registry) {        registry.addMapping("/**")                .allowedOrigins("*")                .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")                .maxAge(3600)                .allowCredentials(true);    }}
复制代码


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


(三)实现文件上传下载


3.1 创建表

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


CREATE TABLE `file` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `filePath` varchar(255) DEFAULT NULL,  `fileName` varchar(255) DEFAULT NULL,  `fileSuffix` varchar(255) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
复制代码


3.2 编写实体类

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


@Data@AllArgsConstructor@NoArgsConstructor@Getter@Setter@EqualsAndHashCodepublic class Files implements Serializable {
private static final long serialVersionUID=1L; /** * 文件存储路径 */ private String filePath; /** * 文件名称 */ private String fileName; /** * 文件后缀名 */ private String fileSuffix;
}
复制代码


3.3 配置 application.properties

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


server.port=8080
spring.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.Driver
mybatis.mapper-locations=classpath:mapper/*.xmlfile.save-path=E:/temp/files
复制代码


3.4 编写 Controller

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


@RestController@RequestMapping("/api")public class FileController {    @Autowired    private FileService fileService;    //文件上传接口    @RequestMapping(value = "/upload",method = RequestMethod.POST)    public Result upLoadFiles(MultipartFile multipartFile){         //如果文件为空,直接返回错误信息        if (multipartFile.isEmpty()){            return new Result(ResponseCode.FILE_EMPTY.getCode(),ResponseCode.FILE_EMPTY.getMsg(),null);        }        //否则调用service上传文件        return fileService.upLoadFiles(multipartFile);    }
@RequestMapping(value = "/download/{id}",method = RequestMethod.GET) public void downloadFiles(@PathVariable("id") String id, HttpServletRequest request, HttpServletResponse response){ OutputStream outputStream=null; InputStream inputStream=null; //先根据id查到文件信息 Files files = fileService.getFileById(id); String fileName = files.getFileName(); //通过文件信息将文件转化为inputStream inputStream=fileService.getFileInputStream(files); //下载文件需要设置的header response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); // 获取输出流 try { outputStream = response.getOutputStream(); } catch (IOException e) { e.printStackTrace(); }finally { //不要忘记关闭流 try { if (inputStream!=null){ inputStream.close(); } if (outputStream!=null){ outputStream.close(); } } catch (IOException e) { e.printStackTrace(); }
} }
}
复制代码


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


public interface FileService {    /**     * 文件上传接口     * @param file     * @return     */    Result upLoadFiles(MultipartFile file);
/** * 根据id获取文件 * @param id * @return */ Files getFileById(String id);
/** * 根据id获取数据流 * @param files * @return */ InputStream getFileInputStream(Files files);}
复制代码


fileServiceImpl 实现类:


@Servicepublic class FileServiceImpl implements FileService {
@Value("${file.save-path}") private String savePath; @Autowired private FileMapper fileMapper;
@Override public Result upLoadFiles(MultipartFile file) { //设置支持最大上传的文件,这里是1024*1024*2=2M long MAX_SIZE=2097152L; //获取要上传文件的名称 String fileName=file.getOriginalFilename(); //如果名称为空,返回一个文件名为空的错误 if (StringUtils.isEmpty(fileName)){ return new Result(ResponseCode.FILE_NAME_EMPTY.getCode(),ResponseCode.FILE_NAME_EMPTY.getMsg(),null); } //如果文件超过最大值,返回超出可上传最大值的错误 if (file.getSize()>MAX_SIZE){ return new Result(ResponseCode.FILE_MAX_SIZE.getCode(),ResponseCode.FILE_MAX_SIZE.getMsg(),null); } //获取到后缀名 String suffixName = fileName.contains(".") ? fileName.substring(fileName.lastIndexOf(".")) : null; //文件的保存重新按照时间戳命名 String newName = System.currentTimeMillis() + suffixName; File newFile=new File(savePath,newName); if (!newFile.getParentFile().exists()){ newFile.getParentFile().mkdirs(); } try { //文件写入 file.transferTo(newFile); } catch (IOException e) { e.printStackTrace(); } //将这些文件的信息写入到数据库中 Files files=new Files(newFile.getPath(),fileName,suffixName); fileMapper.insertFile(files); return new Result(ResponseCode.SUCCESS.getCode(),ResponseCode.SUCCESS.getMsg(),"数据上传成功"); }
//根据id获取文件信息 @Override public Files getFileById(String id) { Files files = fileMapper.selectFileById(id); return files; } //将文件转化为InputStream @Override public InputStream getFileInputStream(Files files) { File file=new File(files.getFilePath()); try { return new FileInputStream(file); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; }}
复制代码


3.5 对数据库的操作

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


@Mapper@Repositorypublic interface FileMapper {    /**     * 将数据信息插入到数据库     * @param files     */    void insertFile(Files files);
/** * 根据id获取文件 * @param id * @return */ Files selectFileById(String id);}
复制代码


编写对应的 xml 文件


<?xml version="1.0" encoding="UTF8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.javayz.fileuploadanddownload.mapper.FileMapper">    <insert id="insertFile" parameterType="com.javayz.fileuploadanddownload.entity.Files">        insert into file(filepath,filename,filesuffix) values(#{filePath},#{fileName},#{fileSuffix});    </insert>
<select id="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

即可调用下载。


发布于: 2021 年 02 月 25 日阅读数: 19
用户头像

Java鱼仔

关注

你会累是因为你在走上坡路 2020.12.26 加入

微信搜索《Java鱼仔》

评论

发布
暂无评论
基于SpringBoot实现文件的上传下载