基於vue+springboot的檔案上傳(並未前後端分離)

可愛扎發表於2020-11-26

前言

注:本文主要處理前端如何向後端傳參以及後端如何處理

今天在使用vue+springboot實現檔案上傳的時候遇到了諸多問題,查詢相關資料的時候都太散亂了,導致整了一下午才真正完成了檔案上傳功能,所以在此總結一下整個流程,以及需要主要的點,以便以後再次使用,同時讓一些像我這樣學了一半就開跑的人少走些彎路

後端部分

在這裡我先講後端部分,後端的實現其實相較於前端更為簡單(可能因為我個人比較熟悉後端)

後端處理上傳而來的檔案分為以下幾步

  • 獲取專案的絕對路徑
  • 建立檔案目錄
  • 建立檔案
  • 上傳檔案到伺服器本地

那麼下面直接結合註釋看程式碼吧

需要匯入的包(springboot的包就不說了,在這裡只是講檔案上傳)

<!--這個包就是可以使用FileNameUtils-->
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

具體程式碼,能做註釋的都做了

結合註釋閱讀吧

package com.zhage.controller;


import org.apache.commons.io.FilenameUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

@RequestMapping("file")
@RestController
public class FileController {

    /**
     * 傳入的引數是MultipartFile
     * 加入@RequestParam註解表示該引數一定要接受到,接受到的是前端的file
     * 根據自己需求可以有其他引數,這裡就演示檔案上傳
     * @param mf
     * @return
     */
    @PostMapping("upload")
    public String upload(@RequestParam("file")MultipartFile mf) throws IOException {

        /**
         * 獲取專案絕對路徑
         * 最終檔案上傳是需要絕對路徑的
         * 相當於給要上傳的位置定個座標
         * classpath:就可以去獲得resources的目錄
         * 具體classpath:獲得resources的原因就得自己去探索了,本文主要是講檔案上傳
         * 這裡不去除first的話這個路徑開頭會有一個/,雖然沒有什麼影響
         */
        String absPath = ResourceUtils.getURL("classpath:").getPath().replaceFirst("/","") + "static/files";
        /**
         * 建立檔案目錄
         * 根據自己的需求
         * 在這我就以當前時間建立
         */
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
        //檔案的目錄應該為絕對路徑+目錄名
        String dirPath = absPath+"/"+sdf.format(new Date());
        //通過這個路徑建立目錄
        File dir = new File(dirPath);
        //如果不存在就建立該目錄
        if(!dir.exists()){
            dir.mkdirs();
        }
        /**
         * 建立檔案
         * 檔名字就根據自己的需求而定
         * 我這裡為了方便,就叫cutezha吧
         */
        //先獲取檔案本身的名字
        String oldName = mf.getOriginalFilename();
        //使用FileNameUtils獲取副檔名,這裡獲取的沒有.所以手動加上
        String extension = "."+FilenameUtils.getExtension(oldName);
        String fileName = "cutezha"+extension;
        //上傳檔案
        mf.transferTo(new File(dir,fileName));
        /**
         * 將資料返回給前端,我這裡就直接將路徑返回了
         * 注意這裡用dirPath才是斜槓,如果使用dir則是反斜槓
         */
        return dirPath+"/"+fileName;
    }
}

那麼後端就完成了,其中有些可以根據自己的需求更改,下面就是前端,由於我本身前端學的一塌糊塗,所以註釋就較少

前端部分

前端部分由於學的很差,所以理解可能沒後端這麼好,希望指出

前端上傳也可分為以下幾步

  • 上傳檔案到input
  • 獲取input裡的檔案
  • 通過axios非同步傳給後端存入伺服器本地

原生vue的axios非同步

這裡通過axios請求了/file/upload,下面直接看前端程式碼

<!doctype html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div id="app">
            <form action="">
                <!--給該input標籤繫結了change事件,繫結到了iii並且通過$event將該標籤傳遞進去-->
                檔案上傳:: <input type="file" @change="iii($event)" ref="file">
                <input type="button" @click="submitForm">
            </form>
        </div>
        <script type="text/javascript">
            const app = new Vue({
                el: '#app',
                data() {
                    return {
                        file: ''
                    };
                },
                methods: {
                    submitForm: function (event) {
                        /**
                     * 這句也可以獲得file
                     * this.file = this.$refs.file.files[0];
                     * 甚至可以通過原生js實現
                     */
                        //通過formdata將檔案存入
                        //除了file,可以將想要向後端傳遞的引數寫進fd
                        fd = new FormData();
                        fd.append("file", this.file);
                        axios({
                            url: 'http://localhost:8080/file/upload',   //所要請求的地址
                            data: fd,       //攜帶的引數
                            method: 'post',   //請求方式
                            headers: {
                                //請求頭很重要,我看見有人說可以不寫,但我不寫不行
                                'Content-Type': 'multipart/form-data',
                            }
                        }).then((res)=>{
                            console.log(res.data);
                        });
                    },
                    iii:function (e){
                        //次函式主要是將input裡的檔案存入data裡的file裡
                        alert(e.target);
                        this.file=e.target.files[0];
                    }
                }
            })
        </script>
    </body>
</html>

執行效果

由於我在iii函式中彈出了一下
在這裡插入圖片描述

在這裡插入圖片描述

點選上傳
在這裡插入圖片描述

去資料夾檢視

在這裡插入圖片描述

使用elementui下的el-upload元件

不太清楚該元件的底層原理是如何實現的,這裡就把程式碼貼上吧,原理還是一樣的,但是file本來就在元件裡面,就不用了獲取了,傳入其他你想要的引數就可以了,這裡就不再掩飾

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>歡迎註冊</title>
        <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <script src="https://unpkg.com/element-ui/lib/index.js"></script>
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    </head>
    <body>
        <div class="login-box" id="app" >
            <el-form >
                <!--action="http://localhost:8181/ctbuc/file/upload"-->
                <el-form-item label="頭 像:" prop="userimg">
                    <el-upload
                               class="avatar-uploader"
                               :show-file-list="false"
                               action="http://localhost:8080/file/upload"
                               :data="你要傳的"
                               >
                        <img v-if="imageUrl" :src="imageUrl" class="avatar">
                        <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                    </el-upload>
                </el-form-item>
            </el-form>
        </div> 
    </body>
後面js沒啥好看的,因為都在elupload裡處理完了

</html>


                  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
                    </el-upload>
                </el-form-item>
            </el-form>
        </div> 
    </body>
後面js沒啥好看的,因為都在elupload裡處理完了

</html>

相關文章