1. 程式人生 > 實用技巧 >Springboot檔案上傳下載

Springboot檔案上傳下載

Springboot檔案上傳下載

檔案的上傳操作

前端程式碼

<form action="http://localhost:8091/file" method="post" 
      enctype="multipart/form-data">
    <input name="fileImage" type="file" />
    <input type="submit" value="提交"/>
</form>

服務端controller

@RequestMapping("/upload")
public String file(MultipartFile fileImage) {
    String fileDirPath = "D:/images"; // 存放位置
    File dirFile = new File(fileDirPath); 
    // 判斷檔案目錄是否存在
    if (!dirFile.exists()) {
        // 如果目錄沒有, 則應該新建目錄
        dirFile.mkdir();
    }
    // 準備檔案上傳路徑, 路徑 + 檔名稱
    String fileName = fileImage.getOriginalFilename(); // 獲取檔名
    File realFile = new File(fileDirPath + "/" + fileName); // 儲存磁碟路徑 + 檔名拼接
    // 將位元組資訊輸出到檔案中
    try {
        fileImage.transferTo(realFile); // 儲存到指定的路徑
        return "檔案上傳成功";
    } catch (IOException e) {
        e.printStackTrace();
        return "檔案上傳失敗";
    }
}

檔案下載操作

下載操作也是非常的簡單, 我們只需要用流的形式返回到客戶端即可

別看長, 其實沒多少程式碼

@RequestMapping("/download")
@ResponseBody
public String downloadFile(HttpServletResponse response) {
    String fileName = "aaa.txt";// 設定檔名,即使用者下載得到檔案的名字(可以和磁碟中的檔名不同)
    if (fileName != null) {
        //設定檔案路徑
        String filePath = "D:/file/001.txt"; // 要下載的檔案位置
        File file = new File(filePath);
        if (file.exists()) {
            // 關於: application/octet-stream
            // 1、只能提交二進位制,而且只能提交一個二進位制,如果提交檔案的話,只能提交一個檔案,後臺接收引數只能有一個,而且只能是流(或者位元組陣列)
            // 2、屬於HTTP規範中Content-Type的一種
            // 3、很少使用
            response.setContentType("application/octet-stream");
            // response.setHeader("content-type", "application/octet-stream"); // 也可以這樣寫
            response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);// 設定檔名
            byte[] buffer = new byte[1024];
            FileInputStream fis = null;
            BufferedInputStream bis = null;
            try {
                fis = new FileInputStream(file);
                bis = new BufferedInputStream(fis);
                OutputStream os = response.getOutputStream();
                int i = bis.read(buffer);
                while (i != -1) {
                    os.write(buffer, 0, i);
                    i = bis.read(buffer);
                }
                System.out.println("success"); // 下載成功返回資訊
            } catch (Exception e) {
                e.printStackTrace();
            } finally { // 關閉流
                if (bis != null) {
                    try {
                        bis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    return null; // 下載失敗返回資訊
}

擴充套件: 上傳圖片並校驗

上傳圖片是經常有的操作, 所以在上傳圖片的時候也要對檔案進行校驗, 防止不符合規範的檔案或者偽裝的木馬病毒等, 例如:

  1. 校驗檔案的有效性
  2. 校驗檔案是否為惡意程式
  3. 提高使用者簡餐圖片的效率 分目錄儲存
  4. 為了防止重名圖片的提交 自定義檔名
  5. 實現圖片的物理上傳
  6. 準備一個訪問的虛擬路徑

Controller編寫

@Autowarld
private FileService fileService;

@RequestMapping("/pic/upload")
public ImageVO upload(MultipartFile uploadFile) {
    return fileService.upload(uploadFile); // 呼叫service進行儲存圖片
}

Service編寫(介面略)

service類-結構

@Service
public class FileServiceImpl implements FileService {
	@Override
    public ImageVO upload(MultipartFile uploadFile) {
        
    }
}

1.校驗檔案字尾

service中定義一個localDirPath靜態變數, 用於儲存支援的圖片你字尾, 例如:

private static Set<String> imageTypeSet = new HashSet<>();
static {
    imageTypeSet.add(".jps");
    imageTypeSet.add(".png");
    imageTypeSet.add(".gif");
    imageTypeSet.add("/bmp");
    //.....其他省略
}

upload方法中

// 1. 圖片的型別 (1) 利用正則表示式   (2) 利用集合的方式進行校驗Set 資料是否存在即可
String fileName = uploadFile.getOriginalFilename();
// 獲取字尾 並轉為全小寫
String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
if (!imageTypeSet.contains(fileType)) { // 如果字尾沒在集合中, 則上傳失敗
    return ImageVO.fail();
}

2.檢驗是否為圖片

upload方法中

//  2. 如何判斷檔案是否為惡意程式, 是否有圖片的屬性
// 2.1 將上傳檔案型別利用圖片API進行轉化
try {
    BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
    // 2.2 校驗是否有圖片的特有屬性 高度, 寬度
    int width = bufferedImage.getWidth();
    int height = bufferedImage.getHeight();
    // 2.3 校驗寬度和高度是否有值
    if (width == 0 || height == 0) {
        return ImageVO.fail();
    }
} catch (IOException e) {
    e.printStackTrace();
    return ImageVO.fail();
}

3.分目錄儲存

service中定義屬性, 表示檔案儲存的位置根路徑

private String localDirPath = "D:/images"; // 定義本地磁碟目錄

upload方法中

// 3. 實現分目錄儲存:
// 方案1: 利用hash之後每隔2-3位擷取之後拼接
// 方案2: 以時間為單位進行分割   /yyyy/MM/dd/ 這裡使用方案2, 方案1自行腦補
// 3.1 利用工具的API將時間轉化為執行的格式
String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
// 3.2 動態生成檔案目錄 2部分=根目錄+時間目錄
String localDir = localDirPath + datePath;
// 3.3 判斷目錄是否存在, 如果不存在則新建目錄
File dirFile = new File(localDir);
if (!dirFile.exists()) {
    dirFile.mkdirs(); // 如果不存在, 則新建目錄
}

4.自定義檔名稱

使用UUID自定義名稱

//4. 防止檔案重名, 需要自定義檔名稱 UUID
//4.1 生成uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
//4.2動態生成檔名稱
String uuidFileName = uuid + fileType;

5.儲存上傳的檔案

// 5. 實現檔案的上傳
String realFilePath = localDir + uuidFileName;
// 5.1 封裝檔案的真實物件
File imageFile = new File(realFilePath);
// 5.1 實現檔案的儲存
try {
    uploadFile.transferTo(imageFile);
} catch (IOException e) {
    e.printStackTrace();
    return ImageVO.fail();
}