Vue+ElementUI+SpringMVC实现图片上传和回显
Vue+ElementUI+SpringMVC實(shí)現(xiàn)圖片上傳和table回顯
在之前我們已經(jīng)講過了 Vue+ElementUI+SpringMVC實(shí)現(xiàn)分頁 。
而我們也常遇到表單中包含圖片上傳的需求,并且需要在table中顯示圖片,所以這里我就講一下結(jié)合后端的SpringMVC框架如何實(shí)現(xiàn)圖片上傳并提交到表單中,在table表格中回顯照片。
本案例對應(yīng)的開源項(xiàng)目地址請看我的GitHub倉庫:
-
優(yōu)雅的入門SpringBoot+Mybatis,實(shí)現(xiàn)簡單的CRUD
-
優(yōu)雅的實(shí)現(xiàn)電商項(xiàng)目中搜索功能,整合SSM+Redis+Shiro+Solr框架,教你使用Vue+ElementUI寫一個(gè)炫酷的后端頁面
寫在前面
本篇博文主要講Vue.js+ElementUI如何實(shí)現(xiàn)圖片上傳和提交表單,前端技術(shù)會講多一點(diǎn),因此:
- 如果你對SpringMVC文件上傳和下載不是很清楚,請查看我這篇博文: SpringMVC實(shí)現(xiàn)文件上傳和下載
- 因?yàn)榘咐赟SM框架,如果你你對SSM框架不是很清楚,請查看我這篇博文:SSM框架整合 GitHub
準(zhǔn)備
首先,請一定閱讀一下我的 SpringMVC實(shí)現(xiàn)文件上傳和下載 本篇博文將不在詳細(xì)講這部分內(nèi)容。
前端:
你會用到以下技術(shù):
Vue.js
Vue-resource.js
ElementUI
我們將實(shí)現(xiàn)的效果是什么呢?
圖片上傳:
table展示:
思路分析
想要實(shí)現(xiàn)圖片上傳和table的回顯,讓我們先分析以下實(shí)現(xiàn)思路:
圖片上傳和表單提交
那么你就要明白圖片上傳和表單提交是兩個(gè)功能,其對應(yīng)不同的接口,表單中并不是保存了這個(gè)圖片,而僅僅是保存了儲存圖片的路徑地址。我們需要分析以下幾點(diǎn):
1、圖片如何上傳,什么時(shí)候上傳?
圖片應(yīng)該在點(diǎn)擊upload上傳組件的時(shí)候就觸發(fā)了對應(yīng)的事件,當(dāng)選擇了要上傳的圖片,點(diǎn)擊確定的時(shí)候就請求了后端的接口保存了圖片。也就是說你在瀏覽器中彈出的選擇框中選擇了要上傳的圖片,當(dāng)你點(diǎn)擊確定的一瞬間就已將圖片保存到了服務(wù)器上;而再點(diǎn)擊提交表單的時(shí)候,儲存在表單中的圖片數(shù)據(jù)僅僅是剛才上傳的圖片存儲地址。
2、如何獲取到已經(jīng)上傳的圖片的儲存地址?
因?yàn)樵跒g覽器上傳選擇框被確定選擇的瞬間已經(jīng)請求了后端接口保存了圖片,我們該怎么知道圖片在哪里儲存呢?
- 前端: 比如我們使用了ElementUI提供的上傳組件,其就存在一個(gè)上傳成功的回調(diào)函數(shù):on-success,這個(gè)回調(diào)函數(shù)被觸發(fā)的時(shí)間點(diǎn)就是圖片成功上傳后的瞬間,我們就是要在這個(gè)回調(diào)函數(shù)觸發(fā)的時(shí)候獲取到圖片儲存的地址。
- 后端: 上面講了獲取地址,這個(gè)地址就是后端返回給前端的數(shù)據(jù)(JSON格式)。因?yàn)楹蠖藞D片上傳接口配置圖片儲存的地址,如果圖片上傳成功,就將圖片儲存的地址以JSON格式返回給前端。
3、如何提交表單
說如何提交表單,這就顯得很簡單了,因?yàn)樯厦嫖覀円呀?jīng)完成了:1、圖片成功上傳;2、獲取到了圖片在服務(wù)器上的儲存地址。利用Vue的雙向綁定思想,在圖片成功上傳的回調(diào)函數(shù)on-success中獲取到后端返回的圖片儲存地址,將這個(gè)地址賦值給Vue實(shí)例data(){}中定義的表單對象。這樣在提交表單的時(shí)候僅需要將這個(gè)表單對象發(fā)送給后端,保存到數(shù)據(jù)庫就行了。
圖片在table的回顯
想要將圖片回顯到table表格中其實(shí)很簡單,前提只要你在數(shù)據(jù)庫中保存了正確的圖片儲存地址;在table表格中我們僅需要在<td>列中新定義一列<td><img src="圖片的地址"/></td>即可完成圖片回顯。渲染table數(shù)據(jù)的時(shí)候循環(huán)給<img>中的src賦值數(shù)據(jù)庫中保存的圖片url即可。
后端實(shí)現(xiàn)
圖片上傳接口
注意: 關(guān)于SpringMVC如何實(shí)現(xiàn)文件上傳和下載,請看我的博文: SpringMVC實(shí)現(xiàn)文件上傳和下載 。這里我給出代碼,就不再解釋了(#.#):
這里我將文件上傳和下載接口單獨(dú)抽離在一個(gè)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) {//獲取文件在服務(wù)器的儲存位置String path = request.getSession().getServletContext().getRealPath("/upload");File filePath = new File(path);System.out.println("文件的保存路徑:" + path);if (!filePath.exists() && !filePath.isDirectory()) {System.out.println("目錄不存在,創(chuàng)建目錄:" + filePath);filePath.mkdir();}//獲取原始文件名稱(包含格式)String originalFileName = picture.getOriginalFilename();System.out.println("原始文件名稱:" + originalFileName);//獲取文件類型,以最后一個(gè)`.`為標(biāo)識String type = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);System.out.println("文件類型:" + type);//獲取文件名稱(不包含格式)String name = originalFileName.substring(0, originalFileName.lastIndexOf("."));//設(shè)置文件新名稱: 當(dāng)前時(shí)間+文件名稱(不包含格式)Date d = new Date();SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");String date = sdf.format(d);String fileName = date + name + "." + type;System.out.println("新文件名稱:" + fileName);//在指定路徑下創(chuàng)建一個(gè)文件File targetFile = new File(path, fileName);//將文件保存到服務(wù)器指定位置try {picture.transferTo(targetFile);System.out.println("上傳成功");//將文件在服務(wù)器的存儲路徑返回return new Result(true,"/upload/" + fileName);} catch (IOException e) {System.out.println("上傳失敗");e.printStackTrace();return new Result(false, "上傳失敗");}} }為什么返回一個(gè)Result數(shù)據(jù)類型?
注意這個(gè)Result是我自己聲明的一個(gè)實(shí)體類,用于封裝返回的結(jié)果信息,配合@RestController注解實(shí)現(xiàn)將封裝的信息以JSON格式return給前端,最后看下我定義的Result:
public class Result implements Serializable {//判斷結(jié)果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... }表單提交接口
表單提交大家都比較熟悉了,配合圖片上傳,僅僅是在實(shí)體類中多了一個(gè)字段存放圖片的URL地址:
@RestController @RequestMapping("/instrument") public class InstrumentController {//注入@Autowiredprivate 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, "發(fā)生未知錯誤");} }如上
大家可能會疑惑這個(gè)為什么返回Result類型的數(shù)據(jù)? 答:為了前端方便判斷接口執(zhí)行成功與否。因?yàn)槲仪岸耸褂玫氖?strong>HTML頁面,想要從后端域?qū)ο笾腥?shù)據(jù)顯然就有點(diǎn)不現(xiàn)實(shí)了。
我寫Controller的時(shí)候定義了全局的@RestController注解,和@Controller注解的區(qū)別是,前者多了@ResponseBody注解,這樣整合Controller類返回的數(shù)據(jù)都將給自動轉(zhuǎn)換成JSON格式。
前端實(shí)現(xiàn)
實(shí)現(xiàn)圖片上傳
這里我使用了ElementUI的文件上傳組件: 官方文檔
配合ElementUI的上傳組件,我們會這樣定義(這是form表單中的一部分):
<el-form-item label="圖片"><el-uploadref="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"這個(gè)參數(shù),與我們普通的文件上傳表單是不同的。
了解幾個(gè)參數(shù):
-
ref ref是Vue原生參數(shù),用來給組件注冊引用信息。引用信息將會注冊到父組件的$refs對象上,如果定義在普通的DOM元素上,那么$refs指向的就是DOM元素。
-
action action表示此上傳組件對應(yīng)的上傳接口,此時(shí)我們使用的是后端Controller定義的接口
-
name name表示當(dāng)前組件上傳的文件字段名,需要和后端的上傳接口字段名相同 。
-
list-type 文件列表的類型,主要是文件列表的樣式定義。這里是卡片化。
-
:limit 最大允許上傳的文件個(gè)數(shù)。
-
file-list 上傳的文件列表,這個(gè)參數(shù)用于在這個(gè)上傳組件中回顯圖片,包含兩個(gè)參數(shù):name、url如果你想在這個(gè)文件上傳組件中咱叔圖片,賦值對應(yīng)的參數(shù)即可顯示,比如更新數(shù)據(jù)時(shí),其表單樣式完全和添加表單是相同的。但是table中回顯圖片是完全不需要用這個(gè)方式的。
-
:on-exceed 上傳文件超出個(gè)數(shù)時(shí)的鉤子函數(shù)。
-
:before-upload 上傳文件前的鉤子函數(shù),參數(shù)為上傳的文件,返回false,就停止上傳。
-
:on-preview 點(diǎn)擊文件列表中已上傳的文件時(shí)的鉤子函數(shù)
-
:on-success 文件上傳成功的鉤子函數(shù)
-
:on-remove 文件列表移除時(shí)的鉤子函數(shù)
-
:src 圖片上傳的URL。
JS部分
//設(shè)置全局表單提交格式 Vue.http.options.emulateJSON = true;new Vue({el: '#app',data(){return{//文件上傳的參數(shù)dialogImageUrl: '',dialogVisible: false,//圖片列表(用于在上傳組件中回顯圖片)fileList: [{name: '', url: ''}],}},methods(){//文件上傳成功的鉤子函數(shù)handleSuccess(res, file) {this.$message({type: 'info',message: '圖片上傳成功',duration: 6000});if (file.response.success) {this.editor.picture = file.response.message; //將返回的文件儲存路徑賦值picture字段}},//刪除文件之前的鉤子函數(shù)handleRemove(file, fileList) {this.$message({type: 'info',message: '已刪除原有圖片',duration: 6000});},//點(diǎn)擊列表中已上傳的文件事的鉤子函數(shù)handlePreview(file) {},//上傳的文件個(gè)數(shù)超出設(shè)定時(shí)觸發(fā)的函數(shù)onExceed(files, fileList) {this.$message({type: 'info',message: '最多只能上傳一個(gè)圖片',duration: 6000});},//文件上傳前的前的鉤子函數(shù)//參數(shù)是上傳的文件,若返回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代碼,主要是定義一些鉤子函數(shù),這里我么里梳理一下邏輯:
1、點(diǎn)擊ElementUI的上傳組件,瀏覽器自動彈出文件上傳選擇窗口,我們選擇要上傳的圖片。
2、選擇好了要上傳的圖片,點(diǎn)擊彈窗右下角的確定按鈕觸發(fā)JS中定義的鉤子函數(shù)。
3、首先觸發(fā)的鉤子函數(shù)是beforeUpload(file)函數(shù),其中的參數(shù)file即代表當(dāng)前上傳的文件對象,beforeUpload()定義了對上傳文件格式校驗(yàn)。如果不是允許的格式就彈出錯誤信息,并阻止文件上傳,若我那件格式允許,則繼續(xù)執(zhí)行。
4、通過了beforeUpload()函數(shù)的校驗(yàn),文件開始調(diào)用后端接口將數(shù)據(jù)發(fā)送給后端。文件的字段名:picture,格式:multipart/form-data,雖然我們的表單沒有定義enctype="multipart/form-data"屬性,但是HTTP請求頭會自動設(shè)置為multipart/form-data類型。
5、這時(shí),如果后端邏輯沒有錯誤,已經(jīng)正常的將圖片上傳到服務(wù)器上了,可以在指定文件夾中查看到已上傳的圖片,那么此時(shí)JS中會自動調(diào)用handleSuccess()鉤子函數(shù),因?yàn)槲覀冊O(shè)置后端上傳接口上傳成功返回的數(shù)據(jù)是文件的保存路徑:
那我們就將這個(gè)路徑通過Vue的雙向綁定,賦值給表單對象的字段picture,那么提交表單的時(shí)候,該字段對應(yīng)的值就是這個(gè)路徑了。
6、如果我們再點(diǎn)擊上傳文件按鈕,就會觸發(fā)onExceed()函數(shù),因?yàn)槲覀冊O(shè)置的limit最多上傳一個(gè)。
7、如果點(diǎn)擊圖片中的刪除按鈕,就會觸發(fā)handleRemove()函數(shù),并刪除此圖片。
8、如果點(diǎn)擊了已上傳的文件列表,就會觸發(fā)handlePreview()函數(shù)。
實(shí)現(xiàn)表單提交
表單提交就比較簡單了,就是觸發(fā)對應(yīng)的click事件,觸發(fā)其中定義的函數(shù),將已在data(){}中定義的表單數(shù)據(jù)發(fā)送給后端接口:
提交數(shù)據(jù):
后端接口
@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, "發(fā)生未知錯誤"); }數(shù)據(jù)庫中保存的數(shù)據(jù):
實(shí)現(xiàn)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-columnlabel="運(yùn)行狀態(tài)"width="80"prop="operatingStatus"></el-table-column> </el-table>因?yàn)槭褂肰ue,根據(jù)其雙向綁定的思想,再結(jié)合Element-UI提供渲染表格的方式是在<el-table>的:data中指定對應(yīng)要渲染的數(shù)據(jù)即可。
注意 ElementUI渲染table的方式是:1、<el-table>中定義:data;2、<el-table-column>中定義prop="data中的參數(shù)"。但是因?yàn)槲覀円@示的是圖片而不是文本數(shù)據(jù),所以要在<img>中定義:src="data中的變量"即可實(shí)現(xiàn)渲染。
后端就是正常的查詢數(shù)據(jù)庫數(shù)據(jù)即可了,為什么數(shù)據(jù)庫中保存了這個(gè)URL圖片就能直接顯示到HTML中,請看我這篇博文: SpringMVC實(shí)現(xiàn)文件上傳和下載
作者:TyCoding 鏈接:https://www.jianshu.com/p/decd9e45f1bf總結(jié)
以上是生活随笔為你收集整理的Vue+ElementUI+SpringMVC实现图片上传和回显的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IntelliJ IDEA 使用教程(2
- 下一篇: 采用 Vue 编写的功能强大的 Swag