图片上传 el+node后端+数据库
模版部分:
鼠标悬浮到头像的部分就出现下拉框显示可以修改头像,
el-upload是隐藏的,可能只是为了实现on-change函数和before-upload函数吧
这块做的确实有点马虎了。
修改头像 退出登录 <!-- 选取文件 -->
import { ref, computed,nextTick } from \'vue\'import { useAllDataStore } from \'../stores\'import { useRouter } from \'vue-router\'// import { ElMessage,ElUpload } from \'element-plus\'import { handleAvatarChange } from \'@/services/editService.js\'const store = useAllDataStore()import defaultAvatar from \'@/assets/images/user-default.png\'const getImageUrl = computed(() => { return store.state.avatar||defaultAvatar; })// 监听状态变化(调试用)watch( () => store.state.avatar, (newVal, oldVal) => { console.log(\'头像更新了:\', newVal, oldVal) }, { immediate: true } // 立即执行一次)const uploadRef = ref(null)function handleUpdateAvatar() { console.log(\'handleUpdateAvatar\') uploadRef.value.$el.querySelector(\'input\').click()}// 上传前的校验,比如限制文件类型、大小等function beforeAvatarUpload(file) { const isJPG = file.type === \'image/jpeg\' || file.type === \'image/png\'; const isLt2M = file.size / 1024 / 1024 { store.clean(); router.push(\'/login\')}
前端发送请求部分:
export const handleAvatarChange=async (file)=> { try { // 创建 FormData 对象,用于上传文件 const formData = new FormData(); formData.append(\'file\', file.raw); // 调用后端接口上传头像,这里的接口地址根据实际后端定义填写 const res = await axios.post(`${API_URL}/updateAvatar`, formData, { headers: { \'Content-Type\': \'multipart/form-data\', \'Authorization\':`Bearer ${localStorage.getItem(\'token\')}`, }, withCredentials: true }); if (res.data.code === 200) { // 假设后端返回 code 为 200 表示成功 ElMessage.success(\'头像修改成功\'); // 更新 store 中的头像地址 store.updateImg(res.data.data.avatar); } } catch (error) { // console.error(\'上传头像出错!:\', error); ElMessage.error(\'网络异常,头像修改失败!\'); }}
后端处理请求部分:
import { Router } from \'express\';import multer from \'multer\';import path from \'path\';import { fileURLToPath } from \'url\';import fs from \'fs/promises\';import pool from \'../config/db.js\';import jwt from \'jsonwebtoken\';import { JWT_SECRET } from \'../config/config.js\';import bodyParser from \'body-parser\';const router = Router();// 1. 直接通过 import.meta.url 计算上传目录路径(不使用 __dirname)const currentFileUrl = new URL(import.meta.url); //当前文件完整的地址const currentDirPath = path.dirname(fileURLToPath(currentFileUrl)); // 当前文件所在目录routes的地址const uploadDir = path.join(currentDirPath, \'../public/avatars\'); // 拼接上传目录路径// console.log(\'uploadDir:\',uploadDir);// 初始化上传目录try { await fs.access(uploadDir);} catch { await fs.mkdir(uploadDir, { recursive: true });}// 2. 配置 multer 存储规则const storage = multer.diskStorage({ destination: (req, file, cb) => { cb(null, uploadDir); }, filename: (req, file, cb) => { const safeName = file.originalname.replace(/[^a-zA-Z0-9_.-]/g, \'\'); const uniqueName = `${Date.now()}-${safeName}`; cb(null, uniqueName); //生成唯一文件名 }});// 3. 创建 multer 实例const upload = multer({ limits: { fileSize: 2 * 1024 * 1024 }, fileFilter: (req, file, cb) => { if (file.mimetype.startsWith(\'image/\')) { cb(null, true); } else { cb(new Error(\'只允许上传图片文件!\'), false); } }, storage: storage});// 4.添加认证中间件 const authenticate = (req, res, next) => { const token = req.headers.authorization?.split(\' \')[1]; console.log(req.headers); if (!token) { return res.status(401).json({ code: 401, message: \'未提供Token认证信息!\' }); } try { // 获取发送请求方的token信息,验证发送人 同时在post请求中顺利的修改请求人的数据库字段 const decoded = jwt.verify(token, JWT_SECRET); req.user = decoded; console.log(\'req.user:\',req.user); next(); } catch (error) { res.status(401).json({ code: 401, message: \'这是无效或者过期的Token!\' });}}// 5. 处理头像上传请求router.post(\'/updateAvatar\',authenticate, upload.single(\'file\'), async (req, res) => { try { if (!req.file) { return res.status(400).json({ code: 400, message: \'文件为空,请选择要上传的头像!\' }); } console.log(\'req.file.filename:\',req.file.filename); // 生成图片访问 URL const avatarUrl = `http://localhost:3000/avatars/${req.file.filename}`; // 验证登录态 if (!req.user?.id) { return res.status(401).json({ code: 401, message: \'未登录,无法修改头像\' }); } const userId = req.user.id; // 更新数据库 const [results] = await pool.query( \'UPDATE users SET avatarUrl = ? WHERE id = ?\', [avatarUrl, userId] ); if (results.affectedRows === 0) { return res.status(404).json({ code: 404, message: \'用户不存在,更新失败\' }); } res.status(200).json({ code: 200, message: \'头像修改成功\', data: { avatar: avatarUrl } }); } catch (error) { console.error(\'头像上传失败:\', error); res.status(500).json({ code: 500, message: \'服务器错误,上传失败\' }); }});
因为有文件处理中间件这些的吧所以确实麻烦了些,还有认证中间件,可以自行删减,注意头像要上传原图片,然后对应的格式就是multipart/form-data了 这块content-type我这个项目里