springboot2.3文件上傳以及需要注意的事項

 

 

pom.xml中需要有指定springboot的版本

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.5.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
        <dependency>
		    <groupId>commons-io</groupId>
		    <artifactId>commons-io</artifactId>
		    <version>2.8.0</version>
		</dependency>

使用了springboot自帶的文件上傳,沒有使用commons-fileupload,所以這裏不引入,引入commons-io是使用IOUtils工具類。

        <dependency>
		    <groupId>commons-fileupload</groupId>
		    <artifactId>commons-fileupload</artifactId>
		    <version>1.4</version>
		</dependency>

 

application.properties

#springboot2.X開啓文件上傳與大小限制
spring.servlet.multipart.enabled=true
#表示上傳的單個文件的最大大小,默認爲 1MB
spring.servlet.multipart.max-file-size=1024MB
#表示多文件上傳時文件的總大小,默認爲 10MB
spring.servlet.multipart.max-request-size=1024MB
#表示文件寫入磁盤的閥值,默認爲 0
spring.servlet.multipart.file-size-threshold=0
#表示上傳文件的臨時保存位置
#spring.servlet.multipart.location=E:\\test\\temp
#表示文件是否延遲解析,默認爲 false
spring.servlet.multipart.resolve-lazily=false

 

一、上傳頁面

thymeleaf的單文件上傳頁面:signleupload.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>SpringBoot 單文件上傳頁面</title>
</head>
<body>
<form method="post" action="/fileupload/signleupload" enctype="multipart/form-data">
文件:<input type="file" name="file"><br>
姓名:<input type="text" name="name"/><br>
<input type="submit" value="上傳"><br>
</form>
</body>
</html>

thymeleaf的多文件上傳頁面:mutliupload.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>SpringBoot 多文件上傳頁面</title>
</head>
<body>
<form method="post" action="/fileupload/mutliupload" enctype="multipart/form-data">
文件1:<input type="file" name="file"><br>
文件2:<input type="file" name="file"><br>
文件3:<input type="file" name="file"><br>
<input type="submit" value="上傳"><br>
</form>
</body>
</html>

 

2、文件上傳控制器

FileUploadController.java

package com.imddysc.monitor.controller;

import java.io.File;
import java.io.FileOutputStream;
import java.time.LocalDate;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/fileupload")
public class FileUploadController {
	
	private static final Logger logger = LoggerFactory.getLogger(FileUploadController.class);
	
	@Value("${upload.rootdir}")
	private String uploaddir;
    // /opt/upload
	
	@RequestMapping("/signleupload")
	public String signleUpload(HttpServletRequest request, @RequestParam("file") MultipartFile file) {
				
		String result = "";
		// 判斷文件是否爲空  
        if (!file.isEmpty()) {
            try {
                // 文件保存路徑 
            	String filePath = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename();
            	logger.info("filePath: " + filePath);
            	File localFile = new File(filePath);
            	if(!localFile.getParentFile().exists()) {
            		localFile.getParentFile().mkdirs();
            		localFile.createNewFile();
            	}
                
                /** 第一種,通過byte[] file.getBytes(),FileUtils直接把bytes數組寫入對應文件李 */
            	byte[] bytes1 = file.getBytes();
            	String filePath1 = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename()+".1";
            	logger.info("filePath1: " + filePath1);
            	logger.info("byte[]: " + new String(bytes1, "UTF-8"));
            	logger.info("filegetName: " + file.getName());
            	FileUtils.writeByteArrayToFile(new File(filePath1), bytes1);
            	logger.info("FileUtils.writeByteArrayToFile 已經執行!");
            	
            	
                /** 第二種,通過IOUtils通過流拷貝到新的文件中去 */
            	String filePath2 = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename()+".2";
            	logger.info("filePath2: " + filePath2);
            	IOUtils.copy(file.getInputStream(),new FileOutputStream(filePath2));
            	logger.info("IOUtils.copy 已經執行!");

            	
            	/** 第三種,轉存文件,直接這樣使用會報異常 */
                file.transferTo(localFile);


                result = "文件上傳成功";
            } catch (Exception e) {
            	result = "文件上傳異常";
                e.printStackTrace();
            }
        } else {
        	result = "文件爲空";
        }
        return result;
	}
	
	@RequestMapping("/mutliupload")
	public String mutliUpload(HttpServletRequest request, @RequestParam("file") MultipartFile[] files) {
		String result = "";
		StringBuilder stringBuilder = new StringBuilder();
		for (MultipartFile file : files) {
			try {
				// 文件保存路徑 
	            String filePath = uploaddir + "/"+ LocalDate.now().toString() +"/"+ file.getOriginalFilename();
	            File localFile = new File(filePath);
	            if(!localFile.getParentFile().exists()) {
            		localFile.getParentFile().mkdirs();
            	}


	            /** 轉存文件,需使用第1,2兩種方式來,直接使用 transferTo會有問題 */
	            file.transferTo(localFile);


			} catch (Exception e) {
				stringBuilder.append(file.getOriginalFilename() + " 上傳失敗!");
                e.printStackTrace();
            }
            
		}
		if(StringUtils.isEmpty(stringBuilder.toString())) {
			result = "上傳成功!";
		} else {
			result = stringBuilder.toString();
		}
        return result;
	}
	
	@RequestMapping("/index.html")
	public String index() {
		return "fileupload/index";
	}
	
	@RequestMapping("/signleupload.html")
	public String signleupload() {
		return "fileupload/signleupload";
	}
	
	@RequestMapping("/mutliupload.html")
	public String mutliupload() {
		return "fileupload/mutliupload";
	}
	
	
}

 

 

 

 

java.io.IOException: java.io.FileNotFoundException:

dest 是相對路徑,指向 upload/doc20170816162034_001.jpg
file.transferTo 方法調用時,判斷如果是相對路徑,則使用temp目錄,爲父目錄
因此,實際保存位置爲 C:\Users\xxxx\AppData\Local\Temp\tomcat.372873030384525225.8080\work\Tomcat\localhost\ROOT\upload\doc20170816162034_001.jpg

所以改爲:使用第1和第2種方式,可以保證文件上傳,如果直接使用file.transferTo會有文件不存在的異常。

 

還由一個解決方法是file.transferTo()的目標文件可以先new File(xxxx/xxxx/xxx).getAbsolutePath();這樣也是獲取的覺得路徑,windowns絕對路徑C:\\xx ,D:\\xx 開頭,linux絕對路徑以 /xx/xxx/開頭。

@Value("${file.upload.path}")
private String path = "upload/";
String fileName = file.getOriginalFilename(); 
File dest = new File(new File(path).getAbsolutePath()+ "/" + fileName); 
file.transferTo(dest); // 保存文件 

 

個人覺得如果是在確認目標文件後,可以直接使用IOUtils.copy進行流拷貝,即第二種方案,第一種只適合小文件,佔內存,file.transferTo內部也是流拷貝。也不麻煩。

 

https://blog.csdn.net/SummerX_Z_Y/article/details/107807184

https://blog.csdn.net/qq_44343988/article/details/107826498

接收不到文件的寫法
--html
var files = document.getElementById('myFile').files;
var formData = new FormData();
formData.append('file', files);
這樣寫,後臺的

@RequestParam("file")MultipartFile[] file
file始終是獲取不到文件的

正確寫法
--html
for(i=0; i < files.length; i++){
     formData.append('file', files[i]);
}

 

 

---下載---

response.addHeader("Content-Type", "application/octet-stream");
response.addHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1") + "\".xlsx;filename*=UTF-8''" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1"));

 

//1.設置文件ContentType類型,這樣設置,會自動判斷下載文件類型   
response.setContentType("multipart/form-data");   
//2.設置文件頭:最後一個參數是設置下載文件名(假如我們叫a.pdf)   
response.setHeader("Content-Disposition", "attachment;fileName="+"a.pdf");
application/force-download
@RequestMapping(value = "/weChatDown/{fileId}")
public ResponseEntity<byte[]> weChatFiledownload(@PathVariable("fileId") String fileId, HttpServletResponse response, HttpServletRequest request) throws Exception {
    DsCmsFile dsCmsFile = fileService.get(fileId);
    if (dsCmsFile != null) {
        String filePath = dsCmsFile.getFileUrl();
        String fileName = dsCmsFile.getFileName();
        File file = new File(filePath);
        long size = file.length();
        //爲了解決中文名稱亂碼問題 這裏是設置文件下載後的名稱
        fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
        response.reset();
        response.setHeader("Accept-Ranges", "bytes");
        //設置文件下載是以附件的形式下載
        response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", fileName));
        response.addHeader("Content-Length", String.valueOf(size));

        ServletOutputStream sos = response.getOutputStream();
        FileInputStream in = new FileInputStream(file);
        BufferedOutputStream outputStream = new BufferedOutputStream(sos);
        byte[] b = new byte[1024];
        int i = 0;
        while ((i = in.read(b)) > 0) {
            outputStream.write(b, 0, i);
        }
        outputStream.flush();
        sos.close();
        outputStream.close();
        in.close();
    }
    return new ResponseEntity<>(HttpStatus.OK);

}

 

 

 

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