怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能(mongodb,nodejs,reactjs,开发技术)

时间:2024-05-02 07:23:44 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

本文小编为大家详细介绍“怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

React + Node.js + Mongodb「上传文件」前后端项目结构

前端项目结构

├──README.md├──package-lock.json└──node_modules└──...├──package.json├──public│└──index.html└──src├──App.css├──App.js├──components│└──UploadFiles.js├──http-common.js├──index.js└──services└──UploadFilesService.js

Reactjs 前端部分

  • App.js: 把我们的组件导入到 React 的起始页

  • components/UploadFiles.js: 文件上传组件

  • http-common.js: 使用 HTTP 基础 Url 和标头初始化 Axios。

  • 我们在.env中为我们的应用程序配置端口

  • services/UploadFilesService.js: 这个文件中的函数用于文件上传和获取数据库中文件数据

后端项目结构

├──README.md├──package.json├──pnpm-lock.yaml└──node_modules└──...└──src├──config│└──db.js├──controllers│└──flileUploadController.js├──middleware│└──upload.js├──routes│└──index.js└──server.js

后端项目结构

  • src/db.js 包括 MongoDB 和 Multer 的配置(url、数据库、文件存储桶)。

  • middleware/upload.js:初始化 Multer GridFs 存储引擎(包括 MongoDB)并定义中间件函数。

  • controllers/flileUploadController.js:配置 Rest API

  • routes/index.js:路由,定义前端请求后端如何执行

  • server.js:Node.js入口文件

前端部分-上传文件 React + Axios

配置 React 环境

这里我们使用 pnpm vite 创建一个 React 项目

npxcreate-react-appreact-multiple-files-upload

项目创建完成后,cd 进入项目,安装项目运行需要的依赖包和 Axios 终端分别依次如下命令

pnpminstallpnpminstallaxios

执行完成我们启动项目 pnpm start

可以看到控制台中已经输出了信息,在浏览器地址栏中输入控制台输出的地址,项目已经跑起来了

导入 bootstrap 到项目中

运行如下命令

npminstallbootstrap

bootstrap 安装完成后,我们打开 src/App.js 文件, 添加如下代码

importReactfrom"react";import"./App.css";import"bootstrap/dist/css/bootstrap.min.css";functionApp(){return(<divclassName="container">...</div>);}exportdefaultApp;

初始化 Axios

src 目录下 我们新建 http-common.js文件,并添加如下代码

importaxiosfrom"axios";exportdefaultaxios.create({baseURL:"http://localhost:8080",headers:{"Content-type":"application/json"}});

这里 baseURL 的地址是我们后端服务器的 REST API 地址,要根据个人实际情况进行修改。本教程后文,教你搭建上传文件的后端部分,请继续阅读。

创建上传文件组件

src/services/UploadFilesService.js,这个文件主要的作用就是和后端项目通讯,以进行文件的上传和文件列表数据的获取等

在文件中我们加入如下内容

importhttpfrom"../http-common";constupload=(file,onUploadProgress)=>{letformData=newFormData();formData.append("file",file);returnhttp.post("/upload",formData,{headers:{"Content-Type":"multipart/form-data",},onUploadProgress,});};constgetFiles=()=>{returnhttp.get("/files");};constFileUploadService={upload,getFiles,};exportdefaultFileUploadService;

首先导入我们之前写好的 Axios HTTP 配置文件 http-common.js,并定义一个对象,在对象中添加两个属性函数,作用如下

  • upload:函数以 POST 的方式将数据提交到后端,接收两个参数 fileonUploadProgress

    • file 上传的文件,以 FormData 的形式上传

    • onUploadProgress 文件上传进度条事件,监测进度条信息

  • getFiles: 函数用于获取存储在 Mongodb 数据库中的数据

最后将这个对象导出去

创建 React 文件上传组件

接下来我们来创建文件上传组件,首先组件要满足功能有文件上传,上传进度条信息展示,文件预览,提示信息,文件下载等功能

这里我们使用 React Hooks 和 useState 来创建文件上传组件,创建文件 src/components/UploadFiles,添加如下代码

importReact,{useState,useEffect,useRef}from"react";importUploadServicefrom"../services/UploadFilesService";constUploadFiles=()=>{return();};exportdefaultUploadFiles;

然后我们使用 React Hooks 定义状态

constUploadFiles=()=>{const[selectedFiles,setSelectedFiles]=useState(undefined);const[progressInfos,setProgressInfos]=useState({val:[]});const[message,setMessage]=useState([]);const[fileInfos,setFileInfos]=useState([]);constprogressInfosRef=useRef(null)}

状态定义好后,我们在添加一个获取文件的方法 selectFiles()

constUploadFiles=()=>{...constselectFiles=(event)=>{setSelectedFiles(event.target.files);setProgressInfos({val:[]});};...}

selectedFiles 用来存储当前选定的文件,每个文件都有一个相应的进度信息如文件名和进度信息等,我们将这些信息存储在 fileInfos中。

constUploadFiles=()=>{...constuploadFiles=()=>{constfiles=Array.from(selectedFiles);let_progressInfos=files.map(file=>({percentage:0,fileName:file.name}));progressInfosRef.current={val:_progressInfos,}constuploadPromises=files.map((file,i)=>upload(i,file));Promise.all(uploadPromises).then(()=>UploadService.getFiles()).then((files)=>{setFileInfos(files.data);});setMessage([]);};...}

我们上传多个文件的时候会将文件信息存储在 selectedFiles, 在上面的代码中 我们使用 Array.from 方法将可迭代数据转换数组形式的数据,接着使用 map 方法将文件的进度信息,名称信息存储到 _progressInfos

接着我们使用 map 方法调用 files 数组中的每一项,使 files 中的每一项都经过 upload 函数的处理,在 upload 函数中我们会返回上传文件请求函数 UploadService.uploadPromise 状态

所以 uploadPromises 中存储的就是处于 Promise 状态的上传文件函数,接着我们使用 Promise.all 同时发送多个文件上传请求,在所有文件都上传成功后,我们将会调用获取所有文件数据的接口,并将获取到的数据展示出来。

upload 函数代码如下

constupload=(idx,file)=>{let_progressInfos=[...progressInfosRef.current.val];returnUploadService.upload(file,(event)=>{_progressInfos[idx].percentage=Math.round((100*event.loaded)/event.total);setProgressInfos({val:_progressInfos});}).then(()=>{setMessage((prevMessage)=>([...prevMessage,"文件上传成功:"+file.name,]));}).catch(()=>{_progressInfos[idx].percentage=0;setProgressInfos({val:_progressInfos});setMessage((prevMessage)=>([...prevMessage,"不能上传文件:"+file.name,]));});};

每个文件的上传进度信息根据 event.loadedevent.total 百分比值来计算,因为在调用 upload 函数的时候,已经将对应文件的索引传递进来了,所有我们根据对应的索引设置对应文件的上传进度

除了这些工作,我们还需要在 Effect HookuseEffect() 做如下功能,这部分代码的作用其实 componentDidMount 中起到的作用一致

constUploadFiles=()=>{...useEffect(()=>{UploadService.getFiles().then((response)=>{setFileInfos(response.data);});},[]);...}

到这里我们就需要将文件上传的 UI 代码添加上了,代码如下

constUploadFiles=()=>{...return(<div>{progressInfos&&progressInfos.val.length>0&&progressInfos.val.map((progressInfo,index)=>(<divclassName="mb-2"key={index}><span>{progressInfo.fileName}</span><divclassName="progress"><divclassName="progress-barprogress-bar-info"role="progressbar"aria-valuenow={progressInfo.percentage}aria-valuemin="0"aria-valuemax="100"style={{width:progressInfo.percentage+"%"}}>{progressInfo.percentage}%</div></div></div>))}<divclassName="rowmy-3"><divclassName="col-8"><labelclassName="btnbtn-defaultp-0"><inputtype="file"multipleonChange={selectFiles}/></label></div><divclassName="col-4"><buttonclassName="btnbtn-successbtn-sm"disabled={!selectedFiles}onClick={uploadFiles}>上传</button></div></div>{message.length>0&&(<divclassName="alertalert-secondary"role="alert"><ul>{message.map((item,i)=>{return<likey={i}>{item}</li>;})}</ul></div>)}<divclassName="card"><divclassName="card-header">ListofFiles</div><ulclassName="list-grouplist-group-flush">{fileInfos&&fileInfos.map((file,index)=>(<liclassName="list-group-item"key={index}><ahref={file.url}>{file.name}</a></li>))}</ul></div></div>);};

在 UI 相关的代码中, 我们使用了 Bootstrap 的进度条

  • 使用 .progress 作为最外层包装

  • 内部使用 .progress-bar 显示进度信息

  • .progress-bar 需要 style 按百分比设置进度信息

  • .progress-bar 进度条还可以设置 rolearia 属性

文件列表信息的展示我们使用 map 遍历 fileInfos 数组,并且将文件的 url,name 信息展示出来

最后,我们将上传文件组件导出

constUploadFiles=()=>{...}exportdefaultUploadFiles;

将文件上传组件添加到App组件

importReactfrom"react";import"./App.css";import"bootstrap/dist/css/bootstrap.min.css";importUploadFilesfrom"./components/UploadFiles.js"functionApp(){return(<divclassName="container"><h5>使用React搭建文件上传Demo</h5><divclassName="content"><UploadFiles/></div></div>);}exportdefaultApp;

上传文件配置端口

考虑到大多数的 HTTP Server 服务器使用 CORS 配置,我们这里在根目录下新建一个 .env 的文件,添加如下内容

PORT=8081

项目运行

到这里我们可以运行下前端项目了,使用命令 pnpm start,浏览器地址栏输入 http://localhost:8081/, ok 项目正常运行

文件选择器、上传按钮、文件列表都已经可以显示出来了,但还无法上传。这是因为后端部分还没有跑起来,接下来,我带领大家手把手搭建上传文件的后端部分。

后端部分

后端部分我们使用 Nodejs + Express + Multer + Mongodb 来搭建文件上传的项目,配合前端 Reactjs + Axios 来共同实现文件上传功能。

后端项目我们提供以下几个API

  • POST /upload 文件上传接口

  • GET /files 文件列表获取接口

  • GET /files/[filename] 下载指定文件

配置 Node.js 开发环境

我们先使用命令 mkdir 创建一个空文件夹,然后 cd 到文件夹里面 这个文件夹就是我们的项目文件夹

mkdirnodejs-mongodb-upload-filescdnodejs-mongodb-upload-files

接着使用命令

npminit--yes

初始化项目,接着安装项目需要的依赖包, 输入如下命令

npminstallexpresscorsmultermulter-gridfs-storagemongodb

package.js 文件

{"name":"nodejs-mongodb-upload-files","version":"1.0.0","description":"Node.jsuploadmultiplefilestoMongoDB","main":"src/server.js","scripts":{"test":"echo\"Error:notestspecified\"&&exit1"},"keywords":["node","upload","multiple","files","mongodb"],"license":"ISC","dependencies":{"cors":"^2.8.5","express":"^4.17.1","mongodb":"^4.1.3","multer":"^1.4.3","multer-gridfs-storage":"^5.0.2"}}

配置 MongoDB 数据库

src/config/db.js

module.exports={url:"mongodb://localhost:27017/",database:"files_db",filesBucket:"photos",};

配置文件上传存储的中间件

src/middleware/upload.js

constutil=require("util");constmulter=require("multer");const{GridFsStorage}=require("multer-gridfs-storage");constdbConfig=require("../config/db");varstorage=newGridFsStorage({url:dbConfig.url+dbConfig.database,options:{useNewUrlParser:true,useUnifiedTopology:true},file:(req,file)=>{constmatch=["image/png","image/jpeg","image/gif"];if(match.indexOf(file.mimetype)===-1){constfilename=`${Date.now()}-zhijianqiu-${file.originalname}`;returnfilename;}return{bucketName:dbConfig.filesBucket,filename:`${Date.now()}-zhijianqiu-${file.originalname}`};}});constmaxSize=2*1024*1024;varuploadFiles=multer({storage:storage,limits:{fileSize:maxSize}}).single("file");varuploadFilesMiddleware=util.promisify(uploadFiles);module.exports=uploadFilesMiddleware;

这里我们定义一个 storage 的配置对象 GridFsStorage

  • url: 必须是指向 MongoDB 数据库的标准 MongoDB 连接字符串。multer-gridfs-storage 模块将自动为您创建一个 mongodb 连接。

  • options: 自定义如何建立连接

  • file: 这是控制数据库中文件存储的功能。该函数的返回值是一个具有以下属性的对象:filename, metadata, chunkSize, bucketName, contentType... 我们还检查文件是否为图像 file.mimetypebucketName 表示文件将存储在 photos.chunksphotos.files 集合中。

  • 接下来我们使用 multer 模块来初始化中间件 util.promisify() 并使导出的中间件对象可以与 async-await.

  • single() 带参数的函数是 input 标签的名称

  • 这里使用 Multer API 来限制上传文件大小,添加 limits: { fileSize: maxSize } 以限制文件大小

创建文件上传的控制器

controllers/flileUploadController.js

这个主要用于文件上传,我们创建一个名 upload 函数,并将这个函数导出去

  • 我们使用 文件上传中间件函数处理上传的文件

  • 使用 Multer 捕获相关错误

  • 返回响应

文件列表数据获取和下载

  • getListFiles: 函数主要是获取 photos.files,返回 url, name

  • download(): 接收文件 name 作为输入参数,从 mongodb 内置打开下载流 GridFSBucket,然后 response.write(chunk) API 将文件传输到客户端。

constupload=require("../middleware/upload");constdbConfig=require("../config/db");constMongoClient=require("mongodb").MongoClient;constGridFSBucket=require("mongodb").GridFSBucket;consturl=dbConfig.url;constbaseUrl="http://localhost:8080/files/";constmongoClient=newMongoClient(url);constuploadFiles=async(req,res)=>{try{awaitupload(req,res);if(req.file==undefined){returnres.status(400).send({message:"请选择要上传的文件"});}returnres.status(200).send({message:"文件上传成功"+req.file.originalname,});}catch(error){console.log(error);if(error.code=="LIMIT_FILE_SIZE"){returnres.status(500).send({message:"文件大小不能超过2MB",});}returnres.status(500).send({message:`无法上传文件:,${error}`});}};constgetListFiles=async(req,res)=>{try{awaitmongoClient.connect();constdatabase=mongoClient.db(dbConfig.database);constfiles=database.collection(dbConfig.filesBucket+".files");letfileInfos=[];if((awaitfiles.estimatedDocumentCount())===0){fileInfos=[]}letcursor=files.find({})awaitcursor.forEach((doc)=>{fileInfos.push({name:doc.filename,url:baseUrl+doc.filename,});});returnres.status(200).send(fileInfos);}catch(error){returnres.status(500).send({message:error.message,});}};constdownload=async(req,res)=>{try{awaitmongoClient.connect();constdatabase=mongoClient.db(dbConfig.database);constbucket=newGridFSBucket(database,{bucketName:dbConfig.filesBucket,});letdownloadStream=bucket.openDownloadStreamByName(req.params.name);downloadStream.on("data",function(data){returnres.status(200).write(data);});downloadStream.on("error",function(err){returnres.status(404).send({message:"无法获取文件"});});downloadStream.on("end",()=>{returnres.end();});}catch(error){returnres.status(500).send({message:error.message,});}};module.exports={uploadFiles,getListFiles,download,};

定义路由

routes 文件夹中,使用 Express Routerindex.js 中定义路由

constexpress=require("express");constrouter=express.Router();constuploadController=require("../controllers/flileUploadController");letroutes=app=>{router.post("/upload",uploadController.uploadFiles);router.get("/files",uploadController.getListFiles);router.get("/files/:name",uploadController.download);returnapp.use("/",router);};module.exports=routes;
  • POST /upload: 调用 uploadFiles控制器的功能。

  • GET /files 获取/files图像列表。

  • GET /files/:name 下载带有文件名的图像。

创建 Express 服务器

constcors=require("cors");constexpress=require("express");constapp=express();global.__basedir=__dirname;varcorsOptions={origin:"http://localhost:8081"};app.use(cors(corsOptions));constinitRoutes=require("./routes");app.use(express.urlencoded({extended:true}));initRoutes(app);letport=8080;app.listen(port,()=>{console.log(`Runningatlocalhost:${port}`);});

这里我们导入了 ExpressCors,

  • Express 用于构建 Rest api

  • Cors提供 Express 中间件以启用具有各种选项的 CORS。

创建一个 Express 应用程序,然后使用方法添加cors中间件 在端口 8080 上侦听传入请求。

运行项目并测试

在项目根目录下在终端中输入命令 node src/server.js, 控制台显示

Runningatlocalhost:8080

使用 postman 工具测试,ok 项目正常运行

文件上传接口

怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能

怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能

文件列表接口

怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能

数据库

怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能

React + Node.js 上传文件前后端一起运行

在 nodejs-mongodb-upload-files 文件夹根目录运行后端 Nodejs

nodesrc/server.js

在 react-multiple-files-upload 文件夹根目录运行前端 React

pnpmstart

然后打开浏览器输入前端访问网址:

怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能

读到这里,这篇“怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

本文:怎么使用Reactjs+Nodejs+Mongodb实现文件上传功能的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:Pycharm报错Non-zero exit code (2)如何解决下一篇:

11 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18