ElementUI + express实现头像上传及后台图片保存
ElementUI + express實現頭像上傳及后臺圖片保存
記錄大創項目中的解決方式。只說明基本的實現方法,不代表實際代碼。如果你需要在后臺保存頭像圖片的話。
當然也可以直接使用base64格式保存頭像,雖然有一些缺陷,這樣后臺就不需要保存圖片了,直接保存base64的文本就行。
文章僅是自己個人在項目中的總結,如有不妥和遺漏還請多多指教。
1. 前端部分
先照搬elementUI的官方文檔,再刪刪補補一下(樣式部分暫且省略):
<!-- 設定的屬性在官方文檔里都有說明,就不再贅述 --> <!-- 上傳的地址:http://localhost/uploadAvatar 必須上傳的文件字段名: avatar 可使用附帶的數據:id(可用于驗證),也可以不加用戶在點擊并選擇好圖片后會立即上傳 --> <el-uploadclass="avatar-uploader"action="http://localhost/uploadAvatar"name="avatar":data="{ id }":show-file-list="false":before-upload="beforeAvatarUpload":on-success="handleAvatarSuccess":on-error="handleAvatarError"><img v-if="imageUrl" :src="imageUrl" class="avatar" /><i v-else class="el-icon-plus avatar-uploader-icon"></i> </el-upload><script> export default {data() {return {imageUrl: "",id: '1234'}},methods: {//上傳成功的方法handleAvatarSuccess(res) {if (res.err) return this.$message.error(res.msg);this.$message.success("頭像上傳成功!");},//上傳失敗的方法handleAvatarError() {this.$message.error("未知錯誤");},//上傳之前的處理beforeAvatarUpload(file) {const isJPG = file.type === "image/jpeg" || file.type === "image/png";const isLt2M = file.size / 1024 / 1024 < 2;if (!isJPG) {this.$message.error("上傳頭像圖片只能是 JPG 或者 PNG 格式!");}if (!isLt2M) {this.$message.error("上傳頭像圖片大小不能超過 2MB!");}return isJPG && isLt2M;}} } </script>2. 后臺接口部分
需要使用images模塊:
npm i images --save該模塊的文檔地址:https://www.npmjs.com/package/images
我使用的是formdata格式傳輸的數據。
const express = require('express'); const images = require('images');const router = express.Router(); //二級路由router.use('/uploadAvatar', function (req, res) {//前端的參數使用req.fields獲取,如果獲取不到,請使用express-formidable模塊并提取掛載const id = req.fields.id; //先獲取,實際情況有可能使用//這里提前定義一個圖片保存的路徑,為防止圖片名有可能沖突,我做了一些處理const imgPath = `./img/avatars/${new Date().getTime() + Math.random().toFixed(3) * 1000}.jpg`;return new Promise((resolve, reject) => {try {//前端的文件使用req.files獲取,因為前面的name屬性,文件的字段名改成了avatar//根據文檔保存圖片:images(req.files.avatar.path) .size(1920).save(imgPath, {quality: 80})resolve()}catch {reject()}}).then(() => {res.send({ err: 0, msg: '頭像已上傳'})}).catch(() => res.send({ err: 1, msg: '上傳失敗' })) });module.exports = router;到此為止,基本的前端頭像上傳和后端圖片保存功能就實現了。再作一些補充。
補充:使用數據庫保存用戶的頭像鏈接
如果是在自己的后臺保存了用戶上傳的圖片,同時你開啟了靜態資源服務,希望用戶能直接訪問服務器上的圖片。
這時可能就需要在數據庫的用戶信息表中保存對應的頭像鏈接。
//前面注釋過的都刪了,補充的部分作了注釋const express = require('express'); const images = require('images'); const mysql = require('mysql'); //引入數據庫模塊const router = express.Router();router.use('/uploadAvatar', function (req, res) {const id = req.fields.id; const imgPath = `./img/avatars/${new Date().getTime() + Math.random().toFixed(3) * 1000}.jpg`;return new Promise((resolve, reject) => {try {images(req.files.avatar.path) .size(1920).save(imgPath, {quality: 80})resolve()}catch {reject()}}).then(() => {//對前面圖片的保存路徑作一些處理,加上前綴:const link = imgPath.replace('.', 'http://localhost'); //這樣就產生了頭像的http路徑,我們可以直接根據該地址訪問圖片,如果你開啟了靜態資源服務的話//接下來就是常規的修改信息://將圖片鏈接存入數據庫const connection = mysql.createConnection({host: "localhost",user: "root",password: "",database: "test",});connection.connect(function (err) {err ? console.log("數據庫鏈接失敗") : console.log("鏈接成功!");});connection.query(`update user_info set profile='${link}' where id=${id}`, //根據前端上傳時附帶的id找到對應用戶(err, row) => {if (err) return res.send({ err: 1, msg: '上傳失敗' });res.send({ err: 0, msg: '頭像已上傳'})}}).catch(() => res.send({ err: 1, msg: '上傳失敗' })) });module.exports = router;補充:后臺設置用戶上傳時限
設置用戶多長時間能夠上傳一次頭像。雖然前端也可以做,但后端更加保險。
同時因為后臺是要保存頭像圖片,不排除一些用戶可能惡意刷頭像上傳,如果沒有及時清理會極大的占據并浪費硬盤空間。
當然我也并不知道正規公司是怎么做的,所以這可能有點多余。僅當作一個思路吧。
const timeLimt = {}; //一個全局對象變量router.use('/uploadAvatar', function (req, res) {const id = req.fields.id; //1.接收用戶id// 4.提前判斷當前用戶是否正在時限中,如果是則直接結束if (timeLimit[idCode]) return res.send({ err: 1, msg: '同一用戶三分鐘只能上傳一次!' });const imgPath = `./img/avatars/${new Date().getTime() + Math.random().toFixed(3) * 1000}.jpg`;return new Promise((resolve, reject) => {try {images(req.files.avatar.path) .size(1920).save(imgPath, {quality: 80})resolve()}catch { reject() }}).then(() => {res.send({ err: 0, msg: '頭像已上傳'})//2.每次上傳成功,給全局變量添加一個當前用戶id的屬性并設置值:timeLimit[id] = true; //代表當前用戶正在時限中,無法更改//3. 三分鐘后解除時限setTimeout(() => {timeLimit[id] = false; }, 180000)}).catch(() => res.send({ err: 1, msg: '上傳失敗' })) });module.exports = router;寫完之后再想想,似乎也可以在每次用戶上傳的時候,在數據庫中查詢對應用戶的頭像鏈接,更新之后再將原先保存的圖片直接刪除。
又或者按照設置時限的思路,每次用戶上傳就將頭像路徑和id綁定,再次上傳時就先根據前一次綁定的頭像路徑將該圖片刪除,再綁定到對應id。
這樣就保證服務器上每個用戶只會保存一張頭像圖片,也就不存在多余的頭像圖片,也不用按時清理了。
不過不知道這樣是否會對后臺產生一些壓力。所以暫且保存這個想法吧,畢竟也只是個小項目,我也只是個寫前端的。
補充:確保一個用戶只會保存一張頭像
根據前面的想法,每次用戶上傳就將頭像路徑和id綁定,同一用戶再次上傳時就先根據前一次綁定的頭像路徑將該圖片刪除,再將新頭像路徑綁定到對應id。以此反復,保證服務器上每個用戶只會保存一張頭像圖片。
//思路同設置時限 const id_avatarFile = {}; //一個全局對象變量router.use('/uploadAvatar', function (req, res) {const id = req.fields.id; //2.異步刪除前一次的圖片if (id_avatarFile[idCode]) //如果存在的話fs.unlinkSync(id_avatarFile[idCode], (err) => {if (err) throw err;console.log('刪除成功');})const imgPath = `./img/avatars/${new Date().getTime() + Math.random().toFixed(3) * 1000}.jpg`;return new Promise((resolve, reject) => {try {images(req.files.avatar.path) .size(1920).save(imgPath, {quality: 80})resolve()}catch { reject() }}).then(() => {res.send({ err: 0, msg: '頭像已上傳'})//1. 保存第一次或前一次上傳的頭像鏈接id_avatarFile[idCode] = imgPath; }).catch(() => res.send({ err: 1, msg: '上傳失敗' })) });module.exports = router;實測可以成功,但是這樣會出現一個新問題:每次用戶重新打開界面時,首次上傳時肯定是沒有這條綁定的數據的,也就是為什么我需要先判斷是否存在這樣的數據才能執行刪除文件的操作。這樣每次一定會殘余一張圖片。
所以每次前端新上傳圖片時,第一次需要查詢數據庫并保存“id—路徑”這樣的數據,相當于初始化。之后直接執行上述的流程就可以了,也不用提前判斷是否存在該條數據。
當然代碼也很簡單,就不再贅述了。
總結
以上是生活随笔為你收集整理的ElementUI + express实现头像上传及后台图片保存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: XML的序列化和反序列化 详细介绍
- 下一篇: 以Drools5.5为例说明“规则引擎在