基於SpringBoot實現文件的上傳下載

據說微信搜索《Java魚仔》會變動強哦!java

本文收錄於JavaStarter ,裏面有我完整的Java系列文章,學習或面試均可以看看哦mysql

(一)概述

文件上傳下載一直都是一個系統最經常使用也是最基本的功能點,恰好最近公司的項目上有用到這個功能,因而本身就用SpringBoot也寫了一個簡化的版本,已實現文件的上傳和下載功能。git

(二)建立項目

首先建立一個SpringBoot的項目,接着引入相關的依賴,由於涉及到數據庫的操做,因此依賴會比較多一些。github

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 接口通用返回類編寫

編寫一個接口的通用返回體,這個在以前的博客中我專門寫過,如今就直接拿來用了:web

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
@NoArgsConstructor
public class Result {
    private int code;
    private String message;
    private Object data;
}

2.3 配置一下解決跨域問題的配置類

在SpringBoot中有多種解決跨域的方法,這裏選擇其中一種spring

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

到這裏爲止,基本的項目配置就算結束了,接下來就是功能的實現了。sql

(三)實現文件上傳下載

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 編寫實體類

寫一個文件對象,和數據庫中的字段相對應:apache

@Data
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public 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-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

mybatis.mapper-locations=classpath:mapper/*.xml
file.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實現類:

@Service
public 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
@Repository
public 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 便可調用下載。

相關文章
相關標籤/搜索