基于minio实现图片上传存储及回显

2,856 阅读4分钟

前言

最近预研项目中需要实现图片上传存储,并且返回网络url进行回显,搜了几种方案,最终基于minio存储来实现,这里需要你的minio存储服务器已创建完成,创建服务器的过程可参考:blog.csdn.net/yhj_911/art…

然后我们基于已创建好的minio服务器,后端通过node.js来搭建接口,实现图片上传存储与回显。

基于node.js搭建后端服务接口

这里采用nestjs和eggjs两个框架搭建的后端服务分别来实现图片上传接口,前提是你已经基于这两个框架搭好了后端服务。 如何搭建后端服务参考:

nestjs.bootcss.com/

blog.csdn.net/weixin_3824…

基于nestjs环境下搭建图片上传存储接口

1、在src目录下创建minioSchema(名字自取)文件夹,然后分别创建

minioSchema.controller.ts;minioSchema.module.ts;minioSchema.service.ts 三个文件

2、在minioSchema.service.ts文件中,搭建服务函数

首先下载minio依赖

npm i minio

连接minio服务器

import Minio = require('minio');
const endPoint = '10.**.**.**'   // 服务ip
const secretKey = '******'  // 密码
console.log(process.env,"process.env")
const minioClient = new Minio.Client({
  endPoint: endPoint,
  port: 32666,  // 服务端口
  useSSL: false,
  accessKey: '******', // 账号名
  secretKey: secretKey,
});

编写服务函数

@Injectable()
export class MinioService {
  async uploadImg(fileData,file: Buffer) {
    const bucketName = 'img'
    const fileName = `${new Date().getTime()}_${fileData.mimetype}`
    await minioClient.putObject(bucketName, fileName, file,
       {
      'Content-Type': fileData.mimetype,
    });
    const url = `http://minio.***.net/${bucketName}/${fileName}`
    // 返回可访问的图片url路径
    return  url
  }
}

minioSchema.service.ts完整代码如下

import { Injectable } from '@nestjs/common';

import Minio = require('minio');
const endPoint = '10.**.**.**'   // 服务ip
const secretKey = '******'  // 密码
console.log(process.env,"process.env")
const minioClient = new Minio.Client({
  endPoint: endPoint,
  port: 32666,  // 服务端口
  useSSL: false,
  accessKey: '******', // 账号名
  secretKey: secretKey,
});


@Injectable()
export class MinioService {
  async uploadImg(fileData,file: Buffer) {
    const bucketName = 'img'
    const fileName = `${new Date().getTime()}_${fileData.mimetype}`
    await minioClient.putObject(bucketName, fileName, file,
       {
      'Content-Type': fileData.mimetype,
    });
    const url = `http://minio.***.net/${bucketName}/${fileName}`
    // 返回可访问的图片url路径
    return  url
  }
}

http://minio.***.net 为minio服务外部可访问的域名

2、在minioSchema.controller.ts文件中,搭建服务函数

import { Body, Request, Get, UseInterceptors, Post, Controller, UseGuards, Delete, UploadedFiles } from '@nestjs/common';
import { MinioService } from './minioSchema.service';
import { AnyFilesInterceptor } from '@nestjs/platform-express';
import { Request as Req } from 'express';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags, ApiQuery, ApiOperation } from '@nestjs/swagger'

@Controller('api/minio')
@ApiTags('图片上传')
// @UseGuards(AuthGuard('jwt'))
export class MinioController {
  constructor(
    private readonly MinioService: MinioService,
  ) { }

  @Post('upload')
  @UseInterceptors(AnyFilesInterceptor())
  @ApiOperation({ summary: '图片上传' })
  async uploadImg(@UploadedFiles() files) { 
    const file = files[0];    
    try {
      const url = await this.MinioService.uploadImg(file,file.buffer);
      return {
          code: 0,
          data:url,
          msg: "上传成功",
        }
    } catch (err) {
      console.log(err,"err")
      return{
          code: 11,
          data:null,
          msg: "上传失败",
        }
    }
  }
}

nestjs使用 UseInterceptors,AnyFilesInterceptor,UploadedFiles 来获取上传的文件files

3、在minioSchema.module.ts文件中引用搭建的服务

import { Module } from '@nestjs/common';
import { MinioController } from './minioSchema.controller';
import { MinioService } from './minioSchema.service';

@Module({
  controllers: [MinioController],
  providers: [MinioService]
})
export class MiniosModule {}

4、最后在app.module.ts引用搭建图片相关模块

import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MiniosModule } from './minioSchema/minioSchema.module';
@Module({
  imports: [
    ConfigModule.forRoot(),
    MongooseModule.forRoot(process.env.MONGODB_URL),   
    MiniosModule
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

到此,我们基于nestjs搭建的已有后端服务中,基于minio搭建的图片上传接口就可以了,如果上传成功,直接data中返回可访问的图片url,在前端界面进行回显

5、前端使用图片上传接口

这里直接使用element-plus框架的el-upload来实现

<script setup lang="ts">
import axios from 'axios'
const UploadImage = async (param) => {
  let params = new FormData() //创建form对象
  params.append('files', param.file) //通过append向form对象添加数据
  const res = await axios.post('/api/minio/upload', params, {
    headers: { 'Content-Type': 'multipart/form-data' },
  })
}
</script>
<template>
  <div >
      <el-upload
        class="upload-demo"
        action="string"
        :http-request="UploadImage"
      >
        <el-button type="default">点击上传</el-button>
      </el-upload>
  </div>
</template>  

基于eggjs搭建环境实现图片上传存储接口

1、在controller问价夹下增加minio.ts文件

首先下载minio依赖和fs依赖

npm i minio

连接minio服务器

import Minio = require('minio');
import fs = require('fs');

const endPoint = '10.**.**.**'   // 服务ip
const secretKey = '******'  // 密码
const minioClient = new Minio.Client({
  endPoint: endPoint,
  port: 32666,  // 服务端口
  useSSL: false,
  accessKey: '******', // 账号名
  secretKey: secretKey,
});

创建接口服务函数

import BaseController from './base';
export default class MinioController extends BaseController {
  // minioClient
  public async uploadImg() {
    const bucketName = this.ctx.request.body && this.ctx.request.body.bucketName || 'img';
    const author = this.ctx.request.body && this.ctx.request.body.userName;//body中传的文件,看需求是否需要
    const file = this.ctx.request.files[0];// 从request里面去files文件
    const fileName = `${new Date().getTime()}_${file.filename}`;
    await minioClient.putObject(bucketName, fileName, fs.createReadStream(file.filepath), {
      'Content-Type': file.mime,
    }); // fs.createReadStream(file.filepath),返回一个readStream(文件读取流,输入流)对象。(可读流)
    const url = `http://minio.*****.net/${bucketName}/${fileName}`;   
    // 返回可访问的图片url路径 ,successRes base中封装的返回函数
    this.successRes(url);
  }
}

minio.ts完整代码如下

import BaseController from './base';


import Minio = require('minio');
import fs = require('fs');

const endPoint = '10.**.**.**'   // 服务ip
const secretKey = '******'  // 密码
const minioClient = new Minio.Client({
  endPoint: endPoint,
  port: 32666,  // 服务端口
  useSSL: false,
  accessKey: '******', // 账号名
  secretKey: secretKey,
});

export default class MinioController extends BaseController {
  // minioClient
  public async uploadImg() {
    const bucketName = this.ctx.request.body && this.ctx.request.body.bucketName || 'img';
    const author = this.ctx.request.body && this.ctx.request.body.userName;//body中传的文件,看需求是否需要
    const file = this.ctx.request.files[0];// 从request里面去files文件
    const fileName = `${new Date().getTime()}_${file.filename}`;
    await minioClient.putObject(bucketName, fileName, fs.createReadStream(file.filepath), {
      'Content-Type': file.mime,
    }); // fs.createReadStream(file.filepath),返回一个readStream(文件读取流,输入流)对象。(可读流)
    const url = `http://minio.*****.net/${bucketName}/${fileName}`;   
    // 返回可访问的图片url路径 ,successRes()为 base中封装的返回函数
    this.successRes(url);
  }
}

BaseController为公共返回函数,base.js文件如下


import { Controller } from 'egg';

export default class BaseController extends Controller {
  errorRes(msg: string, code?: number, data?: any) {
    this.ctx.body = {
      code: code || -1,
      msg,
      data,
    };
  }

  successRes(data?: any, msg?: string) {
    this.ctx.body = {
      code: 0,
      msg: msg || '操作成功。',
      data: data ?? null,
    };
  }
}

然后在router.ts中引用,抛出接口

import { Application } from 'egg';

export default (app: Application) => {
  const {
    controller,
    router,
    // io,
  } = app;
 router.post('/api/minio/uploadImg', controller.minio.uploadImg);

到此,我们基于eggjs的环境搭建的图片上传接口就可以使用了,前端使用接口方法和上述是一致的

前端代码:

<script setup lang="ts">
import axios from 'axios'
const UploadImage = async (param) => {
  let params = new FormData() //创建form对象
  params.append('files', param.file) //通过append向form对象添加数据
  const res = await axios.post('/api/minio/upload', params, {
    headers: { 'Content-Type': 'multipart/form-data' },
  })
}
</script>
<template>
  <div >
      <el-upload
        class="upload-demo"
        action="string"
        :http-request="UploadImage"
      >
        <el-button type="default">点击上传</el-button>
      </el-upload>
  </div>
</template>  

备注:

我基于eggjs搭建的后端服务,获取的file文件中有 filepath,所有采用fs.createReadStream(file.filepath),返回一个readStream(文件读取流,输入流)对象来存储图片,在nestjs服务中,获得file文件中没有filepath,不过有二进制数据流对象buffer,所以可以通过直接传buffer存储图片

参考文档:

www.minio.org.cn/

blog.csdn.net/yhj_911/art…

nestjs.bootcss.com/

blog.csdn.net/weixin_3824…