Java實現帶表單參數的文件上傳、下載和文件壓縮打包下載

準備工作

知識準備

  1. SpringBoot
  2. Maven
  3. Spring Data JPA

工具準備
IDE:IDEA

說明

在此項目中, 我將文件上傳的一些參數(例如上傳路徑、下載路徑、文件名等)保存在數據庫當中,這樣更加靈活。當項目部署後,只需要更改數據庫中的數據就可以實現不同的操作,不用再重新部署,但我也將不使用數據庫的寫法保留在代碼中,以供參考

項目結構

在這裏插入圖片描述

實體類

FileConfiguration.java

import lombok.Data;

import javax.persistence.*;

/**
 * Created by FantasticPan on 2018/10/23.
 * 文件配置類,配置上傳路徑、下載路徑、文件名等參數
 */
@Data
@Entity
@Table
public class FileConfiguration {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    //指定下載的文件名字
    //eg:file.docx
    private String downloadFileName; 
    
    //指定生成的zip壓縮包名字
    //eg:file.zip
    private String downloadZipFileName; 
    
    //允許文件上傳類型
    //eg:.txt,.docx,.doc 注意:逗號爲英文符
    private String uploadFileType; 
    
    //提示信息
    //eg:文件內容爲空 !,文件大小限制1M !,文件後綴名有誤 !,提交成功!,提交失敗,請與工作人員聯繫 注意:逗號爲英文符
    private String tips; 
    
    //指定文件上傳的位置
    //eg:windows系統:D:/uploadFies  Linux系統:/file/uploadFiles
    private String uploadFilePath; 
    
    //指定要下載文件的所在路徑
    //eg:windows系統:D:/file  Linux系統:/file
    private String downLoadFilePath; 
}

實體類使用Lombok工具簡化GET、SET方法,不知道的可以直接寫Get、Set方法
特別注意:允許文件上傳類型uploadFileType和提示信息tips在數據庫中逗號分隔符要用英文符

Files.java

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;

/**
 * Created by FantasticPan on 2017/12/5.
 * 文件類,保存上傳文件的一些參數(上傳日期、上傳路徑等)
 */
@Entity
@Table(name = "files")
@Getter
@Setter
@ToString
public class Files implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;
    private String url;
    private Timestamp date;
}

文件上傳,數據庫一般是不保存文件的,只是將文件的位置等信息保存在數據庫中,根據這些信息再到系統中去查找文件

Member.java

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

/**
 * Created by FantasticPan on 2018/1/24.
 * 對象類
 */
@Entity
@Table(name = "member")
@Setter
@Getter
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    String username;
    String password;

    public Member() {}

    public Member(String username,String password) {
        this.username = username;
        this.password = password;
    }
}

這是對象類,帶表單參數上傳文件時使用

DAO層

針對上面的三個實體類創建三個DAO接口,操作數據庫,這裏我使用的持久層數據庫爲Jpa

1.

import com.pan.file.entity.Files;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by FantasticPan on 2017/12/5.
 */
public interface FileRepository extends JpaRepository<Files,Long> {
}

2.

import com.pan.file.entity.FileConfiguration;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

/**
 * Created by FantasticPan on 2018/10/23.
 */
public interface ConfigurationRepository extends JpaRepository<FileConfiguration, Long> {

    @Query("select f.downloadFileName from FileConfiguration f where f.id =?1")
    String findDownloadFileName(Integer id);

    @Query("select f.downloadZipFileName from FileConfiguration f where f.id =?1")
    String findDownloadZipFileName(Integer id);

    @Query("select f.uploadFileType from FileConfiguration f where f.id =?1")
    String findUploadFileType(Integer id);

    @Query("select f.tips from FileConfiguration f where f.id =?1")
    String findTips(Integer id);

    @Query("select f.uploadFilePath from FileConfiguration f where f.id =?1")
    String findUploadFilePath(Integer id);

    @Query("select f.downLoadFilePath from FileConfiguration f where f.id =?1")
    String findDownLoadFilePath(Integer id);
}

3.

import com.pan.file.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by FantasticPan on 2018/1/24.
 */
public interface MemberRepository extends JpaRepository<Member, Long> {
}

1、文件上傳

我將上傳方法進行封裝,方便調用:

import org.springframework.web.multipart.MultipartFile;
import java.io.File;

/**
  * 上傳文件
  */
public static void uploadFile(String filePath, String fileName, MultipartFile multipartFile) throws Exception {
        File file = new File(filePath + fileName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        multipartFile.transferTo(file);
    }

第一個參數是要上傳的位置,如果是本地可以是某一個盤下的文件夾路徑,第二個參數是獲取到的文件名字,第三個參數是我們使用 Multipartfile 來實現文件上傳。
從數據庫中查詢默認查詢主鍵id爲1

上傳方法調用

    @Autowired
    private FileRepository fileRepository;
    @Autowired
    private ConfigurationRepository configurationRepository;

    @PostMapping(value = "/submit")
    @ResponseBody
    public ModelAndView uploadFile(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "file") MultipartFile multipartFile) throws UnsupportedEncodingException {

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        Long length = multipartFile.getSize();//返回的是字節,1M=1024KB=1048576字節 1KB=1024Byte
        String fileName = multipartFile.getOriginalFilename();
        //獲取文件後綴名
        String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase().trim();
        //獲取文件後綴名
        //String prefix = fileName.substring(0,fileName.lastIndexOf("."));

        //String fileType = ".txt,.docx,.doc";
        //String[] typeArray = fileType.split(",");

        //從數據庫查詢上傳的文件類型
        String fileType = configurationRepository.findUploadFileType(1);

        String tips = configurationRepository.findTips(1);
        //String information[] = {"文件內容爲空 !", "文件大小限制1M !", "文件後綴名有誤 !", "提交成功!", "提交失敗,請與工作人員聯繫"};
        String information[] = tips.split(",");

        ModelAndView mav = new ModelAndView();

        if (multipartFile.isEmpty()) {
            mav.setViewName("message");
            mav.addObject("error", information[0]);
            return mav;
        } else if (length > 1048576) {
            mav.setViewName("message");
            mav.addObject("error", information[1]);
            return mav;
        } else if (!Arrays.asList(fileType.split(",")).contains(suffix)) {
            mav.setViewName("message");
            mav.addObject("error", information[2]);
            return mav;
        }

        //生成自定義的Files對象
        Files files = new Files();
        String uploadFilePath = configurationRepository.findUploadFilePath(1);
        String filePath = uploadFilePath + "/" + UUID.randomUUID() + "/";
        
        //路徑寫死的方法
        //String filePath = "d:/uploadFies" + "/" + UUID.randomUUID() + "/";
        //String filePath = request.getSession().getServletContext().getRealPath("/") + "upload/";
        String fileUrl = filePath + fileName;
        
        //設置屬性
        files.setName(fileName);
        files.setUrl(fileUrl);
        files.setDate(new Timestamp(System.currentTimeMillis()));

        try {
            //上傳文件到服務器
            FileUtil.uploadFile(filePath, fileName, multipartFile);
            //數據庫保存文件信息
            fileRepository.save(files);

            mav.setViewName("message");
            mav.addObject("error", information[3]);
            return mav;
        } catch (Exception e) {
            e.printStackTrace();

            mav.setViewName("message");
            mav.addObject("error", information[4]);
            return mav;
        }
    }

在這裏我進行了文件後綴名和大小等一系列的判斷,並將文件的存儲路徑存到了數據庫,這個在後面壓縮文件會用到
這裏的@RequestParam(value = "file") MultipartFile multipartFile中的 multipartFile就是前面說的要給上傳方法傳的第三個參數,當然我這裏使用的是自動注入,value = “file”就是表單中file輸入框name屬性的名字,視圖如下:

form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
</head>
<body>
<!--文件上傳-->
<form action="/submit" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    <button type="submit">提交</button>
</form>
</body>
</html>

注意:表單要加屬性 enctype="multipart/form-data"

2、文件下載

下載方法封裝

import java.io.*;

/**
 * 下載文件
 */
public static void downloadFile(File file, OutputStream output) {
        FileInputStream fileInput = null;
        BufferedInputStream inputStream = null;
        try {
            fileInput = new FileInputStream(file);
            inputStream = new BufferedInputStream(fileInput);
            byte[] buffer = new byte[8192];//1024*8
            int i;
            while ((i = inputStream.read(buffer)) != -1) {
                output.write(buffer,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
                if (fileInput != null)
                    fileInput.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

方法調用

    @RequestMapping(value = "/fileDownload")
    @ResponseBody
    public void downloadFile(HttpServletResponse response) {

        //String fileName = "下學期公式表.doc";
        String fileName = configurationRepository.findDownloadFileName(1);
        //路徑寫死的方法
        //String filePath = "/file/";
        //String filePath = "D:\\file\\";
        //String filePath = "D:/file/";
        String filePath = configurationRepository.findDownLoadFilePath(1);
        File file = new File(filePath, fileName);

        try {
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
            OutputStream output = response.getOutputStream();

            FileUtil.downloadFile(file, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

fileName是要下載文件的名字,filePath是文件的位置,使用IO的File類將二者拼裝在一起

3、文件打包下載

思路:先生成壓縮包,再下載
文件壓縮方法封裝:

import com.pan.match.entity.Files;

import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 壓縮文件
 */
public static void zipFile(File zipPath, List<Files> filesList) {
        FileOutputStream fileOutput;
        ZipOutputStream zipOutput;
        BufferedOutputStream bufferedOutput;
        FileInputStream fileInput = null;
        BufferedInputStream bufferedInput = null;
        try {
            fileOutput = new FileOutputStream(zipPath); //輸出流,zipPath是生成的壓縮包所在路徑
            bufferedOutput = new BufferedOutputStream(fileOutput);
            zipOutput = new ZipOutputStream(bufferedOutput);

            for (int i = 0; i < filesList.size(); i++) {
                Files files = filesList.get(i);
                File filePath = new File(files.getUrl()); // 待壓縮文件路徑
                // 壓縮條目
                ZipEntry entry = new ZipEntry(i + "." + filePath.getName());
                // 讀取待壓縮的文件並寫進壓縮包裏
                fileInput = new FileInputStream(filePath);
                bufferedInput = new BufferedInputStream(fileInput);
                zipOutput.putNextEntry(entry);
                byte[] buffer = new byte[8192];//官方API文檔推薦大小8192
                int num;
                while ((num = bufferedInput.read(buffer)) != -1) {
                    zipOutput.write(buffer, 0, num);
                }
                //不能寫成  int i = bufferedInput.read(buffer);while(i != -1);否則形成死循環,一直寫入
            }

            //關閉IO
            zipOutput.closeEntry();
            fileInput.close();
            bufferedInput.close();
            zipOutput.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

方法調用:

    @RequestMapping(value = "/zipDownload")
    @ResponseBody
    public void downloadZip(HttpServletResponse response) {

        List<Files> filesList = fileRepository.findAll();

        //路徑寫死的方法
        //String zipName = "file.zip";
        //String outPath = "/file/";
        //String outPath = "D:/file/";
        String outPath = configurationRepository.findDownLoadFilePath(1);
        String zipName = configurationRepository.findDownloadZipFileName(1);
        File zipPath = new File(outPath, zipName);//使用IO的File根據路徑獲取文件

        try {
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipName, "UTF-8"));//解決中文名亂碼
            OutputStream output = response.getOutputStream();//得到服務器的輸入流

            FileUtil.zipFile(zipPath, filesList);
            FileUtil.downloadFile(zipPath, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

這裏的fileList就是要壓縮文件所在的路徑,因爲多個文件,所以是集合,這個路徑集合是從數據庫中查詢出來的
outPath是壓縮生成的文件所在位置,zipName是生成壓縮文件的名字

4、帶表單參數的文件上傳

文件上傳方法同上
表單如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
</head>
<body>
<!--帶表單參數的文件上傳-->
<form action="/formFile" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    名字:<input type="text" name="username" /><br/>
    密碼:<input type="password" name="password" /><br/>
    <input type="submit" name="submit" value="提交"/>
</form>
</body>
</html>

控制類:

    /**
     * 帶表單參數的文件上傳
     */
    @PostMapping(value = "/formFile")
    @ResponseBody
    public ModelAndView formUploadFile(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        /*
		或者方法頭這樣寫:
		單文件
	    public ModelAndView formUploadFile(@RequestParam(value = "file") MultipartFile multipartFile) {}
		多文件
	    public ModelAndView formUploadFile(@RequestParam(value = "file") MultipartFile[] multipartFile) {}
		*/

        //List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles("files");
        //for (int i = 0;i<files.size();i++) {
        //    MultipartFile multipartFile = files.get(i);
        //    String file = multipartFile.getName();
        //}

        //單文件上傳,對應上面的方法頭
        MultipartFile multipartFile = ((MultipartHttpServletRequest) request).getFile("file");
        //多文件上傳
        //MultipartFile multipartFile = multipartRequestgetFiles("file").get(0);

        //獲取表單參數
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //生成Member對象,存入數據庫
        Member member = new Member(username, password);

        //返回的是字節,1M=1024KB=1048576字節 1KB=1024Byte
        Long length = multipartFile.getSize();
        String fileName = multipartFile.getOriginalFilename();
        //獲取文件後綴名
        String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase().trim();
        //獲取文件後綴名
        //String prefix = fileName.substring(0,fileName.lastIndexOf("."));

        //指定符合要求的後綴
        //String fileType = ".txt,.docx,.doc";
        //數據庫中查詢符合要求的後綴
        String fileType = configurationRepository.findUploadFileType(1);
        //將字符串通過指定符號轉變爲數組
        //String[] typeArray = fileType.split(",");

        //String information[] = {"文件內容爲空 !", "文件大小限制1M !", "文件後綴名有誤 !", "提交成功!", "提交失敗,請與工作人員聯繫"};
        String tips = configurationRepository.findTips(1);
        String information[] = tips.split(",");
        ModelAndView mav = new ModelAndView();

        if (multipartFile.isEmpty()) {
            mav.setViewName("message");
            mav.addObject("error", information[0]);
            return mav;
        } else if (length > 1048576) {
            mav.setViewName("message");
            mav.addObject("error", information[1]);
            return mav;
        } else if (!Arrays.asList(fileType.split(",")).contains(suffix)) {
            mav.setViewName("message");
            mav.addObject("error", information[2]);
            return mav;
        }

        Files files = new Files();
        //加上UUID,防止路徑重複
        //String filePath = "/file/uploadFiles" + "/" + UUID.randomUUID() + "/";
        //String filePath = request.getSession().getServletContext().getRealPath("/") + "upload/";
        //String filePath = "d:/uploadFies" + "/" + UUID.randomUUID() + "/";
        String uploadFilePath = configurationRepository.findUploadFilePath(1); //eg:windows:D:/uploadFies Linux:/file/uploadFiles
        String filePath = uploadFilePath + "/" + UUID.randomUUID() + "/";
        String fileUrl = filePath + fileName;
        files.setName(fileName);
        files.setUrl(fileUrl);
        files.setDate(new Timestamp(System.currentTimeMillis()));

        try {
            //調用上傳方法
            FileUtil.uploadFile(filePath, fileName, multipartFile);
            //數據庫保存文件的存儲路徑
            fileRepository.save(files);

            memberRepository.save(member);

            mav.setViewName("message");
            mav.addObject("error", information[3]);
            return mav;
        } catch (Exception e) {
            e.printStackTrace();

            mav.setViewName("message");
            mav.addObject("error", information[4]);
            return mav;
        }
    }

其他

message.html信息提示頁面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>信息提示</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
    <script type="text/javascript">
        var time = 3; //時間,秒
        function Redirect() {
            window.location = "http://www.baidu.com";
        }
        var i = 0;
        function dis() {
            document.all.s.innerHTML = "還剩" + (time - i) + "秒";
            i++;
        }
        timer = setInterval('dis()', 1000); //顯示時間
        timer = setTimeout('Redirect()', time * 1000); //跳轉
    </script>
</head>
<body>
<br/><br/><br/><br/>
<center>
    <h1><p th:text="${error}"></p></h1>
    <h1><span id="s"></span></h1>
</center>
</body>
</html>

配置文件:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/fantasticpan?useUnicode=true&amp;characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

spring.thymeleaf.cache=false
spring.jpa.hibernate.ddl-auto=update
spring.jackson.serialization.indent-output=true

#單個文件大小
spring.http.multipart.max-file-size=1MB
#總上傳的數據大小
spring.http.multipart.max-request-size=1MB

server.port=9090

這裏設置了文件上傳大小的限制

SpringBoot2.0之後有了新的寫法

#單個文件大小
spring.servlet.multipart.max-file-size=10Mb
#總上傳的數據大小
spring.servlet.multipart.max-request-size=10Mb

演示

1. 項目運行,這裏我將上面的幾個頁面結合在了一起

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
</head>
<body>
<!--文件上傳-->
<h1>文件上傳</h1>
<form action="/submit" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    <button type="submit">提交</button>
</form>
<br/><br/>
<!--帶表單參數的文件上傳-->
<h1>帶表單參數文件上傳</h1>
<form action="/formFile" method="post" enctype="multipart/form-data">

    <input type="file" name="file"/><br/>
    名字:<input type="text" name="username" /><br/>
    密碼:<input type="password" name="password" /><br/>
    <input type="submit" name="submit" value="提交"/>
</form>
<br/><br/>
<h1>文件下載</h1>
<a href="/fileDownload">下載文件</a><br/>
<a href="/zipDownload">壓縮文件下載</a>
</body>
</html>

在這裏插入圖片描述
界面簡陋請見諒

2. 數據庫配置

在這裏插入圖片描述

3. 測試

3.1 上傳文件

在這裏插入圖片描述
在這裏插入圖片描述
成功!

3.2 帶表單參數的文件上傳

在這裏插入圖片描述
在這裏插入圖片描述
成功!

3.3 下載文件

在這裏插入圖片描述

3.4 下載壓縮包

在這裏插入圖片描述

4. 數據庫信息查看

在這裏插入圖片描述
在這裏插入圖片描述
可以看到數據都是保存成功了的

總結

到此,文件的上傳和下載就完成了

源碼

源碼放在GitHub上了。若有幫助,希望GitHub能給我一個Star,誠摯的感謝!
file

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章