Vue+ElementUI+SpringMVC實現圖片上傳和回顯

Vue+ElementUI+SpringMVC實現圖片上傳和table回顯javascript

在以前咱們已經講過了 Vue+ElementUI+SpringMVC實現分頁html

而咱們也常遇到表單中包含圖片上傳的需求,而且須要在table中顯示圖片,因此這裏我就講一下結合後端的SpringMVC框架如何實現圖片上傳並提交到表單中,在table表格中回顯照片。前端

本案例對應的開源項目地址請看個人GitHub倉庫:vue

<br/>github

寫在前面redis

本篇博文主要講Vue.js+ElementUI如何實現圖片上傳和提交表單,前端技術會講多一點,所以:spring

準備

首先,請必定閱讀一下個人 SpringMVC實現文件上傳和下載 本篇博文將不在詳細講這部份內容。數據庫

前端:

你會用到如下技術:

Vue.js

Vue-resource.js

ElementUI

咱們將實現的效果是什麼呢?

圖片上傳:

table展現:

思路分析

想要實現圖片上傳和table的回顯,讓咱們先分析如下實現思路:

圖片上傳和表單提交

那麼你就要明白圖片上傳和表單提交是兩個功能,其對應不一樣的接口,表單中並非保存了這個圖片,而僅僅是保存了儲存圖片的路徑地址。咱們須要分析如下幾點:

一、圖片如何上傳,何時上傳?

圖片應該在點擊upload上傳組件的時候就觸發了對應的事件,當選擇了要上傳的圖片,點擊肯定的時候就請求了後端的接口保存了圖片。也就是說你在瀏覽器中彈出的選擇框中選擇了要上傳的圖片,當你點擊肯定的一瞬間就已將圖片保存到了服務器上;而再點擊提交表單的時候,儲存在表單中的圖片數據僅僅是剛纔上傳的圖片存儲地址。

二、如何獲取到已經上傳的圖片的儲存地址?

由於在瀏覽器上傳選擇框被肯定選擇的瞬間已經請求了後端接口保存了圖片,咱們該怎麼知道圖片在哪裏儲存呢?

  • 前端: 好比咱們使用了ElementUI提供的上傳組件,其就存在一個上傳成功的回調函數:on-success,這個回調函數被觸發的時間點就是圖片成功上傳後的瞬間,咱們就是要在這個回調函數觸發的時候獲取到圖片儲存的地址。
  • 後端: 上面講了獲取地址,這個地址就是後端返回給前端的數據(JSON格式)。由於後端圖片上傳接口配置圖片儲存的地址,若是圖片上傳成功,就將圖片儲存的地址以JSON格式返回給前端。

三、如何提交表單

說如何提交表單,這就顯得很簡單了,由於上面咱們已經完成了:一、圖片成功上傳;二、獲取到了圖片在服務器上的儲存地址。利用Vue的雙向綁定思想,在圖片成功上傳的回調函數on-success中獲取到後端返回的圖片儲存地址,將這個地址賦值給Vue實例data(){}中定義的表單對象。這樣在提交表單的時候僅須要將這個表單對象發送給後端,保存到數據庫就好了。

圖片在table的回顯

想要將圖片回顯到table表格中其實很簡單,前提只要你在數據庫中保存了正確的圖片儲存地址;在table表格中咱們僅須要在<td>列中新定義一列<td><img src="圖片的地址"/></td>便可完成圖片回顯。渲染table數據的時候循環給<img>中的src賦值數據庫中保存的圖片url便可。

<br/>

後端實現

<br/>

圖片上傳接口

注意: 關於SpringMVC如何實現文件上傳和下載,請看個人博文: SpringMVC實現文件上傳和下載 。這裏我給出代碼,就再也不解釋了(#^.^#):

這裏我將文件上傳和下載接口單獨抽離在一個Controller類中:

import com.instrument.entity.Result;

@RestController
public class UploadDownController {

    /**
     * 文件上傳
     * @param picture
     * @param request
     * @return
     */
    @RequestMapping("/upload")
    public Result upload(@RequestParam("picture") MultipartFile picture, HttpServletRequest request) {

        //獲取文件在服務器的儲存位置
        String path = request.getSession().getServletContext().getRealPath("/upload");
        File filePath = new File(path);
        System.out.println("文件的保存路徑:" + path);
        if (!filePath.exists() && !filePath.isDirectory()) {
            System.out.println("目錄不存在,建立目錄:" + filePath);
            filePath.mkdir();
        }

        //獲取原始文件名稱(包含格式)
        String originalFileName = picture.getOriginalFilename();
        System.out.println("原始文件名稱:" + originalFileName);

        //獲取文件類型,以最後一個`.`爲標識
        String type = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        System.out.println("文件類型:" + type);
        //獲取文件名稱(不包含格式)
        String name = originalFileName.substring(0, originalFileName.lastIndexOf("."));

        //設置文件新名稱: 當前時間+文件名稱(不包含格式)
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String date = sdf.format(d);
        String fileName = date + name + "." + type;
        System.out.println("新文件名稱:" + fileName);

        //在指定路徑下建立一個文件
        File targetFile = new File(path, fileName);

        //將文件保存到服務器指定位置
        try {
            picture.transferTo(targetFile);
            System.out.println("上傳成功");
            //將文件在服務器的存儲路徑返回
            return new Result(true,"/upload/" + fileName);
        } catch (IOException e) {
            System.out.println("上傳失敗");
            e.printStackTrace();
            return new Result(false, "上傳失敗");
        }
    }
}

爲何返回一個Result數據類型?

注意這個Result是我本身聲明的一個實體類,用於封裝返回的結果信息,配合@RestController註解實現將封裝的信息以JSON格式return給前端,最後看下我定義的Result:

public class Result implements Serializable {

    //判斷結果
    private boolean success;
    //返回信息
    private String message;

    public Result(boolean success, String message) {
        this.success = success;
        this.message = message;
    }
    
    public boolean isSuccess() {
        return success;
    }
    
    setter/getter...
}

表單提交接口

表單提交你們都比較熟悉了,配合圖片上傳,僅僅是在實體類中多了一個字段存放圖片的URL地址:

@RestController
@RequestMapping("/instrument")
public class InstrumentController {

    //注入
    @Autowired
    private InstrumentService instrumentService;

    /**
     * 添加
     *
     * @param instrument
     * @return
     */
    @RequestMapping("/save")
    public Result save(Instrument instrument) {
        if(instrument != null){
            try{
                instrumentService.save(instrument);
                return new Result(true,"添加成功");
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        return new Result(false, "發生未知錯誤");
    }
}

如上

你們可能會疑惑這個爲何返回Result類型的數據? 答:爲了前端方便判斷接口執行成功與否。由於我前端使用的是HTML頁面,想要從後端域對象中取數據顯然就有點不現實了。

我寫Controller的時候定義了全局的@RestController註解,和@Controller註解的區別是,前者多了@ResponseBody註解,這樣整合Controller類返回的數據都將給自動轉換成JSON格式。

<br/>

前端實現

<br/>

實現圖片上傳

這裏我使用了ElementUI的文件上傳組件: 官方文檔

配合ElementUI的上傳組件,咱們會這樣定義(這是form表單中的一部分):

<el-form-item label="圖片">
    <el-upload
               ref="upload"
               action="/upload.do"
               name="picture"
               list-type="picture-card"
               :limit="1"
               :file-list="fileList"
               :on-exceed="onExceed"
               :before-upload="beforeUpload"
               :on-preview="handlePreview"
               :on-success="handleSuccess"
               :on-remove="handleRemove">
        <i class="el-icon-plus"></i>
    </el-upload>
    <el-dialog :visible.sync="dialogVisible">
        <img width="100%" :src="dialogImageUrl" alt="">
    </el-dialog>
</el-form-item>

注意,我這裏僅展現了文件上傳的form-item,ElementUI的表單聲明是:<el-form> 注意 表單中不須要指定enctype="multipart/form-data"這個參數,與咱們普通的文件上傳表單是不一樣的。

瞭解幾個參數:

  • ref ref是Vue原生參數,用來給組件註冊引用信息。引用信息將會註冊到父組件的$refs對象上,若是定義在普通的DOM元素上,那麼$refs指向的就是DOM元素。

  • action action表示此上傳組件對應的上傳接口,此時咱們使用的是後端Controller定義的接口

  • name name表示當前組件上傳的文件字段名,須要和後端的上傳接口字段名相同 。

  • list-type 文件列表的類型,主要是文件列表的樣式定義。這裏是卡片化。

  • :limit 最大容許上傳的文件個數。

  • file-list 上傳的文件列表,這個參數用於在這個上傳組件中回顯圖片,包含兩個參數:name、url若是你想在這個文件上傳組件中咱叔圖片,賦值對應的參數便可顯示,好比更新數據時,其表單樣式徹底和添加表單是相同的。可是table中回顯圖片是徹底不須要用這個方式的。

  • :on-exceed 上傳文件超出個數時的鉤子函數。

  • :before-upload 上傳文件前的鉤子函數,參數爲上傳的文件,返回false,就中止上傳。

  • :on-preview 點擊文件列表中已上傳的文件時的鉤子函數

  • :on-success 文件上傳成功的鉤子函數

  • :on-remove 文件列表移除時的鉤子函數

  • :src 圖片上傳的URL。

JS部分

//設置全局表單提交格式
Vue.http.options.emulateJSON = true;

new Vue({
    el: '#app',
    data(){
        return{
            //文件上傳的參數
            dialogImageUrl: '',
            dialogVisible: false,
            //圖片列表(用於在上傳組件中回顯圖片)
            fileList: [{name: '', url: ''}],
        }
    },
    methods(){
   		//文件上傳成功的鉤子函數
        handleSuccess(res, file) {
            this.$message({
                type: 'info',
                message: '圖片上傳成功',
                duration: 6000
            });
            if (file.response.success) {
                this.editor.picture = file.response.message; //將返回的文件儲存路徑賦值picture字段
            }
        },
        //刪除文件以前的鉤子函數
        handleRemove(file, fileList) {
            this.$message({
                type: 'info',
                message: '已刪除原有圖片',
                duration: 6000
            });
        },
        //點擊列表中已上傳的文件事的鉤子函數
        handlePreview(file) {
        },
        //上傳的文件個數超出設定時觸發的函數
        onExceed(files, fileList) {
            this.$message({
                type: 'info',
                message: '最多隻能上傳一個圖片',
                duration: 6000
            });
        },
        //文件上傳前的前的鉤子函數
        //參數是上傳的文件,若返回false,或返回Primary且被reject,則中止上傳
        beforeUpload(file) {
            const isJPG = file.type === 'image/jpeg';
            const isGIF = file.type === 'image/gif';
            const isPNG = file.type === 'image/png';
            const isBMP = file.type === 'image/bmp';
            const isLt2M = file.size / 1024 / 1024 < 2;

            if (!isJPG && !isGIF && !isPNG && !isBMP) {
                this.$message.error('上傳圖片必須是JPG/GIF/PNG/BMP 格式!');
            }
            if (!isLt2M) {
                this.$message.error('上傳圖片大小不能超過 2MB!');
            }
            return (isJPG || isBMP || isGIF || isPNG) && isLt2M;
        },     
    }
});

解釋

如上的JS代碼,主要是定義一些鉤子函數,這裏我麼裏梳理一下邏輯:

一、點擊ElementUI的上傳組件,瀏覽器自動彈出文件上傳選擇窗口,咱們選擇要上傳的圖片。

二、選擇好了要上傳的圖片,點擊彈窗右下角的肯定按鈕觸發JS中定義的鉤子函數。

三、首先觸發的鉤子函數是beforeUpload(file)函數,其中的參數file即表明當前上傳的文件對象,beforeUpload()定義了對上傳文件格式校驗。若是不是容許的格式就彈出錯誤信息,並阻止文件上傳,若我那件格式容許,則繼續執行。

四、經過了beforeUpload()函數的校驗,文件開始調用後端接口將數據發送給後端。文件的字段名:picture,格式:multipart/form-data,雖然咱們的表單沒有定義enctype="multipart/form-data"屬性,可是HTTP請求頭會自動設置爲multipart/form-data類型。

五、這時,若是後端邏輯沒有錯誤,已經正常的將圖片上傳到服務器上了,能夠在指定文件夾中查看到已上傳的圖片,那麼此時JS中會自動調用handleSuccess()鉤子函數,由於咱們設置後端上傳接口上傳成功返回的數據是文件的保存路徑:

那咱們就將這個路徑經過Vue的雙向綁定,賦值給表單對象的字段picture,那麼提交表單的時候,該字段對應的值就是這個路徑了。

六、若是咱們再點擊上傳文件按鈕,就會觸發onExceed()函數,由於咱們設置的limit最多上傳一個。

七、若是點擊圖片中的刪除按鈕,就會觸發handleRemove()函數,並刪除此圖片。

八、若是點擊了已上傳的文件列表,就會觸發handlePreview()函數。

實現表單提交

表單提交就比較簡單了,就是觸發對應的click事件,觸發其中定義的函數,將已在data(){}中定義的表單數據發送給後端接口:

提交數據:

後端接口

@RequestMapping("/save")
public Result save(Instrument instrument) {
    if(instrument != null){
        try{
            instrumentService.save(instrument);
            return new Result(true,"添加成功");
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    return new Result(false, "發生未知錯誤");
}

數據庫中保存的數據:

<br/>

實現table回顯圖片

table回顯圖片也是很簡單的,僅須要在列中增長一列:

<el-table :data="instrument">
    <el-table-column label="圖片" width="130">
        <template scope="scope">
            <img :src="scope.row.picture" class="picture"/>
        </template>
    </el-table-column>
    <el-table-column
         label="運行狀態"
         width="80"
         prop="operatingStatus">
    </el-table-column>
</el-table>

由於使用Vue,根據其雙向綁定的思想,再結合Element-UI提供渲染表格的方式是在<el-table>:data中指定對應要渲染的數據便可。

注意 ElementUI渲染table的方式是:一、<el-table>中定義:data;二、<el-table-column>中定義prop="data中的參數"。可是由於咱們要顯示的是圖片而不是文本數據,因此要在<img>中定義:src="data中的變量"便可實現渲染。

<br/>

後端就是正常的查詢數據庫數據便可了,爲何數據庫中保存了這個URL圖片就能直接顯示到HTML中,請看我這篇博文: SpringMVC實現文件上傳和下載

<br/>

交流

若是你們有興趣,歡迎你們加入個人Java交流技術羣:671017003 ,一塊兒交流學習Java技術。博主目前一直在自學JAVA中,技術有限,若是能夠,會盡力給你們提供一些幫助,或是一些學習方法,固然羣裏的大佬都會積極給新手答疑的。因此,別猶豫,快來加入咱們吧!

<br/>

聯繫

If you have some questions after you see this article, you can contact me or you can find some info by clicking these links.

相關文章
相關標籤/搜索