1. 程式人生 > >Java實現帶表單引數的檔案上傳、下載和檔案打包下載

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) {