如何使用nodejs实现头像上传,上传多个图片并压缩生成大中小三种图片 (基于Koa2演示)

如何使用nodejs实现头像上传,上传多个图片并压缩生成大中小三种图片 (基于Koa2演示)

源码

这里我只是做个演示没有使用分层架构等规范开发流程
本Demo主要用到了
path、fs、koa-multer、jimp库实现上传逻辑

const Koa = require('koa');
const fs = require('fs');
const path = require('path');
const cors = require('@koa/cors');
const Router = require('koa-router');
const Multer = require('koa-multer');
const Jimp = require('jimp');


const app = new Koa();
const router = new Router();

app.use(cors({
    origin: '*',
    allowMethods: ['GET', 'POST'],
    allowHeaders: ['Content-Type', 'Authorization']
}));

const AVATAR_PATH = "./uploads/avatar" //头像路径
const PICTURE_PATH = "./uploads/picture" //图片路径

// 创建的一个 Multer 实例,用于处理头像上传
const avatarUpload = Multer({
    dest: AVATAR_PATH
});
// 创建另一个 Multer 实例,用于处理图片上传
const pictureUpload = Multer({
    dest: PICTURE_PATH
});

// 创建全局信息用于返回图片(不推荐 只是演示用一下)
let GlobalInfofilename = null
let GlobalInfomimetype = null
let GlobalInfosize = null

// 处理单个图片:处理表单中字段名为 'avatar' 的单个文件上传(其实就是中间件)
const avatarHandler = avatarUpload.single('avatar');
// 处理多个图片:
const pictureHandler = pictureUpload.array('picture', 9);


// 保存头像信息
function saveAvatarInfo(ctx, next) {
    const { filename, mimetype, size } = ctx.req.file;

    // 将信息保存到全局(你也可以根据userid去保存到数据库中后期用sql查出来也行)
    // 注意:中间件函数中修改全局变量是一个不推荐的做法,尤其是在并发请求的情况下(这里只是演示一下用法)
    GlobalInfofilename = filename;
    GlobalInfomimetype = mimetype;
    GlobalInfosize = size;
    // 2.将图片地址保存到user表中(TODO...)

    // 4.返回结果
    ctx.body = {
        code: 200,
        message: '上传成功',
        data: {
            filename,
            mimetype,
            size
        }
    }
}

// 查看头像
function viewAvatar(ctx, next) {

    // 你可以根据userid去数据库中查询头像信息,然后返回给前端(这里比较重要的就是filename,mimetype,size)
    // 0.获取用户id到数据库中查询头像信息(TODO...)
    const { userId } = ctx.params;
    console.log("传递的UserId为:", userId)

    // 1.提供图像信息
    ctx.response.set('content-type', GlobalInfomimetype);

    // 2.创建可读流返回出去
    ctx.body = fs.createReadStream(`${AVATAR_PATH}/${GlobalInfofilename}`);
}

// 处理图片生成多种尺寸图片(方案一:不带后缀名保存  ——  很快)
const pictureResize = async (ctx, next) => {
    try {
        // 1.获取所有的图像信息
        const files = ctx.req.files;

        // 2.对图像进行处理(sharp/jimp)
        for (let file of files) {
            const destPath = path.join(file.destination, file.filename);
            console.log(destPath);
            Jimp.read(file.path).then(image => {
                image.resize(1280, Jimp.AUTO).write(`${destPath}-large`);
                image.resize(640, Jimp.AUTO).write(`${destPath}-middle`);
                image.resize(320, Jimp.AUTO).write(`${destPath}-small`);
            });
        }

        await next();
    } catch (error) {
        console.log(error);
    }
}

// 处理图片生成多种尺寸图片(方案二:带后缀名保存  ——  很慢)
// const pictureResize = async (ctx, next) => {
//     try {
//         // 1. 获取所有的图像信息
//         const files = ctx.req.files;

//         // 2. 对图像进行处理(Jimp)
//         for (let file of files) {
//             // 获取文件扩展名
//             const ext = path.extname(file.originalname);

//             // 组合完整的目标路径(包含扩展名)
//             const destPath = path.join(file.destination, `${file.filename}${ext}`);
//             console.log(destPath);

//             // 重命名文件,并保存到本地(添加扩展名)
//             const originalPath = path.join(file.destination, file.filename);
//             fs.renameSync(originalPath, destPath);

//             // 读取文件并生成不同尺寸的图片
//             await Jimp.read(destPath).then(image => {
//                 image.resize(1280, Jimp.AUTO).write(`${destPath}-large${ext}`);
//                 image.resize(640, Jimp.AUTO).write(`${destPath}-middle${ext}`);
//                 image.resize(320, Jimp.AUTO).write(`${destPath}-small${ext}`);
//             });
//         }

//         await next();
//     } catch (error) {
//         console.log(error);
//     }
// }


// 保存多个图片的逻辑
function savePictureInfo(ctx, next) {
    // 1.获取图像信息
    const files = ctx.req.files;
    // const { id } = ctx.xxx; // 你也可以根据id去数据库中查询xxx信息
    // const { xxxid } = ctx.xxx; // 你也可以根据xxxid去数据库中查询xxx信息

    // 2.将所有的文件信息保存到数据库中
    for (let file of files) {
        const { filename, mimetype, size } = file;
        console.log(filename, mimetype, size);
        // 3.将图片地址保存到数据库中(TODO...)
    }
    ctx.body = {
        code: 200,
        message: '上传成功',
    }
}

// 上传头像路由
router.post('/uploadavatar', avatarHandler, saveAvatarInfo);
// 上传多个图片路由
router.post('/uploadavatars', pictureHandler, pictureResize, savePictureInfo);
// 查看头像路由
router.get("/viewavatar/:userId", viewAvatar);

app.use(router.routes()).use(router.allowedMethods());


app.listen(3000, () => {
    console.log('服务启动成功🚀:http://localhost:3000');
});

package.json

{
  "name": "file-upload-and-download",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@koa/cors": "^5.0.0",
    "jimp": "^0.22.12",
    "koa": "^2.15.3",
    "koa-cors": "^0.0.16",
    "koa-multer": "^1.0.2",
    "koa-router": "^12.0.1"
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值