跳至主要内容

實作 Vue 拖拉檔案上傳並透過 Java 後端處理

· 閱讀時間約 4 分鐘
HK Chen
Cloud Engineer

簡單實作 Vue 的拖拉檔案上傳並透過 Ajax 呼叫 Java 後端 API 來處理上傳的檔案內容,後端的部份因為 Server 問題,僅留後端程式碼、注意事項和截圖結果呈現。

Demo 以及 CodePen 部分皆只呈現前端頁面的部份並使用 CDN 的方式引入,而 CodePen 有使用 Bootstrap 的按鈕,上傳 icon 則是 FontAwesome,有需要請自行引入!

以下為前端頁面拖拉檔案或點擊上傳的部份,上傳後可以分析出檔案的一些資訊,上傳完後也會出現刪除檔案的按鈕。而範例的 code 會加上呼叫後端 API 的段落並利用 axios 來呼叫。

前端 Demo

前往 CodePen 觀看完整 Demo

CSS 樣式

.dropZone {
height: 200px;
position: relative;
border: 2px dashed #eee;
}

.dropZone:hover {
border: 2px solid #2e94c4;
}

.dropZone:hover .dropZone-title {
color: #1975A0;
}

.dropZone-info {
color: #A8A8A8;
position: absolute;
top: 50%;
width: 100%;
transform: translate(0, -50%);
text-align: center;
}

.dropZone-title {
color: #787878;
}

.dropZone input {
position: absolute;
cursor: pointer;
top: 0px;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
}

.dropZone-upload-limit-info {
display: flex;
justify-content: flex-start;
flex-direction: column;
}

.dropZone-over {
background: #5C5C5C !important;
opacity: 0.8;
border: 2px solid #2e94c4;
}

.dropZone-uploaded {
height: 200px;
position: relative;
border: 2px dashed #eee;
}

.dropZone-uploaded-info {
display: flex;
flex-direction: column;
align-items: center;
color: #A8A8A8;
position: absolute;
top: 50%;
width: 100%;
transform: translate(0, -50%);
text-align: center;
}

.removeFile {
width: 200px;
}

.btn-primary {
color: #fff;
background-color: #1170C8;
border-radius: 5px;
}

HTML 結構

<div id="app">
<div v-if="!file">
<div :class="['dropZone', dragging ? 'dropZone-over' : '']"
@dragestart="dragging = true"
@dragenter="dragging = true"
@dragleave="dragging = false">
<div class="dropZone-info" @drag="onChange">
<!-- font-awesome upload icon -->
<span class="fa fa-cloud-upload dropZone-title"></span>
<span class="dropZone-title">Drop file or click to upload</span>
<div class="dropZone-upload-limit-info">
<div>extension support: txt</div>
<div>maximum file size: 5 MB</div>
</div>
</div>
<input type="file" @change="onChange">
</div>
</div>

<div v-else class="dropZone-uploaded">
<div class="dropZone-uploaded-info">
<span class="dropZone-title">Uploaded</span>
<button type="button"
class="btn btn-primary removeFile"
@click="removeFile">
Remove File
</button>
</div>
</div>

<div class="uploadedFile-info">
<div>fileName: {{ file.name }}</div>
<div>fileSize(bytes): {{ file.size }}</div>
<div>extension:{{ extension }}</div>
</div>
</div>

JavaScript 實作

<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>
var app = new Vue({
el: '#app',
data() {
return {
file: '',
dragging: false
}
},
methods: {
onChange(e) {
// 判斷拖拉上傳或點擊上傳的 event
var files = e.target.files || e.dataTransfer.files;

// 預防檔案為空檔
if (!files.length) {
this.dragging = false;
return;
}

this.createFile(files[0]);
},

createFile(file) {
// 附檔名判斷
if (!file.type.match('text.*')) {
alert('please select txt file');
this.dragging = false;
return;
}

// 檔案大小判斷
if (file.size > 5000000) {
alert('please check file size no more than 5 MB');
this.dragging = false;
return;
}

this.file = file;
this.dragging = false;

// axios post 的 url 記得更換你自己的 api url
let json = new FormData();
json.append('uploadFile', this.file);

axios.post('http://localhost:8080/uploadFile', json, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
if (res.data !== null && res.data.length > 1) {
console.log(res.data);
}
});
},

removeFile() {
this.file = '';
}
},

computed: {
// 前端擷取附檔名
extension() {
return (this.file) ? this.file.name.split('.').pop() : '';
}
}
});

後端 Java 部分

SpringMVC 為例子:

Configuration multipartResolver

重要配置

如果沒有設定會噴 error log

applicationContext-webapp.xml 底下添加:

<!-- for <form ... enctype="multipart/form-data" /> -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- The maximum file size in bytes -->
<property name="maxUploadSize" value="5000000" />
</bean>

Controller 實作

@Autowired 
FileService fileService;

@PostMapping("uploadFile")
@ResponseBody
public String searchSimilarDocumentByDocument(@RequestParam("uploadFile") MultipartFile file) {
return fileService.txtToString(file);
}

Service 實作

public static String txtToString(MultipartFile file) throws IOException {
return new String(file.getBytes(), "UTF-8").trim();
}

測試結果

測試輸入

  • 檔案名稱: test.txt
  • 檔案內容: 測試文件

測試輸入

Log 結果

Log 結果

注意事項

Code 都是簡單的範例應用,礙於 server 緣故,後端的實作基本上就是貼重要的 code 和擷取結果,之後前端利用 axios 接收到剛剛的結果在看要怎麼去處理像是輸出的某些地方之類的。

而真實使用的時候一些例外處理還有副檔名前後端處理,最後前端要取的什麼訊息或錯誤訊息都得記得補上哦。