這一章我要介紹的是檔案上傳的功能,這篇看似不起眼,有人會認為說網頁檔案上傳不就點下upload file按鈕後再選擇檔案然後按一個上傳按鈕而已,
不!!!!! 你大錯特錯!!!!!
為什麼我要這樣說?
首先要先分四個層面來講
1.上傳檔案有沒有被偽造了?
2.上傳檔案大小定義,上傳檔案的次數需不需要限制,上傳檔案的名稱有跟你的目的地有無重複
3.上傳哪種檔案?
4.上傳的模式,多檔案上傳我是不是要一個一個點按鈕?
先看這四點好了,開發網站的你是否曾經都遇過這些問題了?
上傳檔案雖然沒什麼但是卻往往都是資訊安全最薄弱的一層,但是我們不是要討論資訊安全,所以我們先以功能開發為主
有時間會再來跟大家說明簡單的防護措施,不過最好避免你的檔案上傳功能有使用外掛工具
ex: CKEditor
如果不想要使用thymeleaf靜態資源載入的方式,你可以上網查詢你要的webjars
將他放入你的pom.xml設定檔
ex:我可能需要jquery,讓Maven來管理我們的webjars
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.2.4</version>
</dependency>
<form method="POST" enctype="multipart/form-data" id="UploadForm">
<input type="file" name="files"/><br/>
<button type="submit" value="Submit" id="btnSubmit"/>
</form>
<script>
$(function(){
$("#btnSubmit").click(function (event) {
//ajax提交的話她會一直重新run程式直到回傳,你可以將此行註解使用開發者工具看一下console就知道了
event.preventDefault();
uploadFile();
});
uploadFile = function() {
// 取得form
var form = $('#UploadForm')[0]; //取得HTML中第一個form id為UploadForm
var data = new FormData(form); //將form內的所有訊息打包成FormData object
$("#btnSubmit").prop("disabled", true);
$.ajax({
type: "POST", //使用POST傳輸,檔案上傳只能用POST
enctype: 'multipart/form-data', //將資料加密傳輸 檔案上傳一定要有的屬性
url: "/api/upload/multi", //要傳輸對應的接口
data: data, //要傳輸的資料,我們將form 內upload打包成data
processData: false, //防止jquery將data變成query String
contentType: false,
cache: false, //不做快取
async : false, //設為同步
timeout: 1000000, //設定傳輸的timeout,時間內沒完成則中斷
success: function (data) {
$("#result").text(data);//填入提示訊息到result標籤內
console.log("SUCCESS : ", data);
$("#btnSubmit").prop("disabled", false);
},
error: function (e) {
$("#result").text(e.responseText); //填入提示訊息到result標籤內
console.log("ERROR : ", e);
$("#btnSubmit").prop("disabled", false);
}
})
}
})
</script>
我的名稱設為 UploadFileModel.java
package com.tutorial.Model;
import org.springframework.web.multipart.MultipartFile;
public class UploadFileModel {
private String extraField;
/**
*
* 單一檔案使用MultipartFile資料型態
* 多檔案上傳可使用MultipartFile
*/
private MultipartFile[] files;
public String getExtraField() {
return extraField;
}
public void setExtraField(String extraField) {
this.extraField = extraField;
}
public MultipartFile[] getFiles() {
return files;
}
public void setFiles(MultipartFile[] files) {
this.files = files;
}
}
在Class設定一個全域變數為檔案上傳的目的,你可以設定在application.properties
private static String UPLOADED_FOLDER = ".//upload//";
// 多個檔案上傳的接口
@PostMapping("/api/upload/multi")
@ResponseBody
public ResponseEntity<?> uploadFileMulti(
@RequestParam("files") MultipartFile[] uploadfiles) {
// 取得檔案名稱
String uploadedFileName = Arrays.stream(uploadfiles).map(x -> x.getOriginalFilename())
.filter(x -> !StringUtils.isEmpty(x)).collect(Collectors.joining(" , "));
if (StringUtils.isEmpty(uploadedFileName)) {
return new ResponseEntity("請選擇檔案!", HttpStatus.OK);
}
try {
saveUploadedFiles(Arrays.asList(uploadfiles));
} catch (IOException e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity("成功上傳 - "
+ uploadedFileName, HttpStatus.OK);
}
檔案上傳存檔的方法
//將檔案儲存
private void saveUploadedFiles(List<MultipartFile> files) throws IOException {
for (MultipartFile file : files) {
if (file.isEmpty()) {
continue; //繼續下一個檔案
}
byte[] bytes = file.getBytes();
Path path = Paths.get(UPLOADED_FOLDER + file.getOriginalFilename());
Files.write(path, bytes);
}
}
1.此範例為多檔案上傳,如果你想知道更多種檔案上傳的方式你可以看我的參考資料,內有三種檔案上傳方式
2.此範例我是用Controller不是RestController,在接收的接口要加上@ResponseBody
3.@RequestParam() 為接收從POST過來的參數
4.upload Model中的 MultipartFile為檔案陣列型態
5.return後我們會傳送HttpStatus返回時可以處理各種不同的HttpStatus
6.ajax傳輸要很小心的避免使用,如果再ajax函式內使用console你就知道進入了ajax傳輸,javascript還是持續的在等待接收與執行回傳資料
(https://www.mkyong.com/spring-boot/spring-boot-file-upload-example-ajax-and-rest/ )
(https://spring.io/guides/gs/uploading-files/ )
假日會介紹建構RESTful Web Service將剩下的會員 CRUD完成
如果你喜歡我的文章,請大家辦個帳號來幫我點個訂閱吧!!
感謝觀看我文章的人 累阿~~
請問您的 UploadFileModel
在哪邊使用到 ??
UploadFileModel 只有使用 ModelAttribute 時才會用到。
可以看參考資料中的 3.1.3