Используйте (Node+MongoDB) для создания простейшего образа или сетевого диска.

Vue.js

1 статья Происхождение

Проведя столько времени в Наггетсах за бесплатную проституцию, я всегда чувствую, что должен что-то производить, иначе мне будет неловко.Посмотрев различные вложения, выложенные в Интернете, я чувствую, что это может быть сложно для новичков, поэтому я приведу это сегодня Статьи о загрузке и скачивании вложений в Node+Mongodb. Проект относительно прост, поэтому каталог прост, и то, что вы узнали, может быстро построить небольшую карту сетевого диска или что-то в этом роде. Спасибо Наггетс за ваши отличные статьи, я получил повышение и прибавку 😁 (я мальчик)

2 стартера

2.1 Концепция

Сначала мы должны понять👉Файловое хранилище MongoDB (GridFS)что, потому что мы все основаны наGridFSдля хранения файлов

2.2 Что нам нужно

После понимания общей концепции можно переходить к установке необходимых плагинов

  • 👉express(Мне не нужно больше говорить об этом)
  • 👉body-parser(Node анализирует промежуточное ПО тела)
  • 👉ejs(Шаблонный движок, быстрая разработка не требует разделения передней и задней части. Заинтересованные партнеры могут использовать Vue/React для создания небольшого сетевого диска)
  • 👉gridfs-stream(Легкая передача файлов в MongoDB GridFS и обратно.)
  • 👉method-override(Форму формы мы используем для простой загрузки, т.к. форма формы не поддерживает метод запроса поставить/удалить, поэтому она устроена, и друзья могут использовать Ajax сами, так что не надо таких хлопот)
  • 👉mongoose(Незаменимый плагин для подключения к mongodb)
  • 👉multer(Multer — промежуточное ПО node.js для обработки данных, состоящих из нескольких частей/форм, в основном для загрузки файлов. Оно написано поверх busboy для максимальной эффективности.)
  • 👉multer-gridfs-storage(Подсистема хранения GridFS компании Multer сохраняет загруженные файлы непосредственно в MongoDb.)
  • 👉nodemon(горячее обновление)

Это все, что нам нужно для подготовки

// 懒人复制区域

npm install express body-parser ejs gridfs-stream method-override mongoose multer multer-gridfs-storage
// or
yarn add express body-parser ejs gridfs-stream method-override mongoose multer multer-gridfs-storage

2.3 Инициализировать проект

// 可自行补充信息
// npm init

Затем создайте новый файл записи app.js в корневом каталоге и просмотры страниц/index.ejs.

3 Теперь проект начинается

3.1 Сначала закончите основы

Вводим установленный нами пакет, а затем запускаем и смотрим

const express = require('express')
const path = require('path')
const crypto = require('crypto')
const mongoose = require('mongoose')
const multer = require('multer')
const GridFsStorage = require('multer-gridfs-storage')
const GridFsStream = require('gridfs-stream')
const methodOverride = require('method-override')
const bodyParser = require('body-parser')

const app = express()

app.set('view engine', 'ejs') // 设置模板引擎

app.use(bodyParser.json()) 
app.use(methodOverride('_method'))

app.get('/', (req, res) => {
        res.render('index')
    })
})

const port = 5000
app.listen(port, () => {
    console.log(`App listering on port ${port}`)
})

Вообще говоря, если app.js запущен, мы можем увидеть интерфейс в views/index.ejs, зайдя в браузере по адресу http://localhost:5000. Если нет, проверьте, сообщает ли консоль об ошибке самостоятельно.

3.2 Подключитесь к нашей базе данных MongoDB

Локальная база данных mongodb, которую я использую здесь, такая же онлайн, мы можем использоватьNoSQL manager for mongdbДля просмотра данных в нашей базе создаем новую коллекцию, меня зовут grid_uploads. Так что если вы подключитесь, он также подключит набор

// 数据库的链接
const mongoURL = 'mongodb://localhost:27017/grid_uploads'

const connect = mongoose.createConnection(mongoURL, {
    useNewUrlParser: true,
    useUnifiedTopology: true
})

Вы можете попробовать написать некоторые данные в NoSQL, вы можете обратиться к блогу для конкретного использования👉【MongoDB】Учебное пособие по NoSQL Manager для MongoDB

3.3 Украсьте интерфейс (views/index.ejs)

Мы как front-end инженер, который два года был front-end инженером, мы уже натренировали пиксельные глаза, мы не должны делать интерфейс таким уродливым, правильно, глаза его не пройдут, поэтому просто используем bootstrap4 сделать интерфейс.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <style>
        img {
            width: 100%;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6 m-auto">
                <h2 class="text-center display-4 my-4">Mongo文件上传</h2>
                <form action="/upload" method="POST" enctype="multipart/form-data">
                    <div class="custom-file mb-3">
                        <input type="file" name="file" id="file" class="custom-file-input">
                        <label for="file" class="custom-file-label">选择文件</label>
                    </div>
                    <input class="btn btn-primary btn-block" type="submit" value="提交">
                </form>
                <hr>
            </div>
        </div>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>

</html>

Затем, если мы запросим http://localhost:5000, мы должны увидеть что-то вроде этого

3.4 Выполните необходимую обработку

// 定义gfs变量,后续我们进行数据库文件操作的时候可不能少
let gfs;
connect.once('open', () => {
    // 监听数据库开启,通过 gridfs-stream 中间件和数据库进行文件的出入控制
    gfs = GridFsStream(connect.db, mongoose.mongo)
    gfs.collection('upload')
    // 它会在我们数据库中建立 upload.files(记录文件信息)  upload.chunks(存储文件块)
})

// 使用 multer-gridfs-storage Multer 中间件来讲我们上传的附件直接存储到MongoDb
const storage = new GridFsStorage({
    url: mongoURL,
    file: (req, file) => {
        return new Promise((resolve, reject) => {
            // 下面注释部分是给文件进行重命名的,如果想要原文件名称可以自行使用 file.originalname 返回,
            // 建议有时间的小伙伴存储两个文档,一个记录原文件名,一个记录加密文件名,然后返回到页面的时候可以将中文名返回去
            
            // crypto.randomBytes(16, (err, buf) => {
            //     if (err) {
            //         return reject(err)
            //     }
            //     const filename = buf.toString('hex') + path.extname(file.originalname)
            //     const fileinfo = {
            //         filename,
            //         bucketName: 'upload'
            //     }
            //     resolve(fileinfo)
            // })
            const fileinfo = {
                filename: new Date() + '-' + file.originalname,
                bucketName: 'upload'
            }
            resolve(fileinfo)
        })
    }
})

const upload = multer({ storage })

3.5 Напишите интерфейс для загрузки нашего первого файла

app.post('/upload', upload.single('file'), (req, res) => {
    res.redirect('/')
})

Это выглядит просто, пожалуйста, имейте в виду эти несколько вещей

  • в представлениях/index.ejs(тип ввода=файлУказанное имя совпадает с именем интерфейсаupload.single('file')Такой же
  • После загрузки файла мы перенаправляем обратно на нашу домашнюю страницу. На данный момент мы видим, что в наших двух документах есть данные в NoSql.

Это загрузка.chunks

это загрузка.файлы

3.6 Получить всю информацию о нашем файле

Получите все наши документы

app.get('/files', (req, res) => {
    // 通过查找返回一个数组对象回去
    gfs.files.find().toArray((err, files) => {
        if (!files || files.length === 0) {
            return res.status(404).json({
                err: '文件不存在!'
            })
        }
        return res.json(files)
    })
})

Мы можем выполнить некоторые операции по благоустройству, например, мы можем загрузить изображение, и если мы вернемся в интерфейс, оно будет отображаться как изображение, а остальные будут отображаться в формате тега (кликабельно для загрузки), Таким образом, мы можем сделать интерфейс представлений/index.ejs, украсить (синтаксис ejs действительно громоздкий), изменить порядок и добавить кнопки удаления.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文件上传</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/css/bootstrap.min.css"
        integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <style>
        img {
            width: 100%;
        }
    </style>
</head>

<body>
    <div class="container">
        <div class="row">
            <div class="col-md-6 m-auto">
                <h2 class="text-center display-4 my-4">Mongo文件上传</h2>
                <form action="/upload" method="POST" enctype="multipart/form-data">
                    <div class="custom-file mb-3">
                        <input type="file" name="file" id="file" class="custom-file-input">
                        <label for="file" class="custom-file-label">选择文件</label>
                    </div>
                    <input class="btn btn-primary btn-block" type="submit" value="提交">
                </form>
                <hr>
            </div>
        </div>
        <div class="row">
            <% if(files){ %>
            <% files.forEach(function(file){ %>
            <div class="col-sm card card-body m-3  col-md-2">
                <% if(file.isImage){ %>
                <img src="image/<%= file.filename %>" />
                <% } else { %>
                <a href="download/<%= file.filename %>"><%= file.filename %></a>
                <%}%>
                    <form action="/files/<%= file._id%>?_method=DELETE" method="POST">
                <button class="btn btn-danger btn-block mt-4">删除</button>
                </form>
            </div>
            <% }) %>
            <% }else { %>
            <p class="card card-body text-center display-4 my-4">文件不存在</p>
            <% } %>
        </div>
    </div>
</body>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
    integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
    crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
    integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
    crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.0/dist/js/bootstrap.min.js"
    integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI"
    crossorigin="anonymous"></script>

</html>

Чтобы получить переменную files в ejs, мы должны переписать интерфейс get('/') для чтения информации о файле базы данных и вывода ее на страницу при доступе к localhost:5000

app.get('/', (req, res) => {
    gfs.files.find().toArray((err, files) => {
        if (!files || files.length === 0) {
            res.render('index', { files: false })
            return
        }
        files.map(file => {
            // 如果是以下图片类型我们就在前端展示出来,其余一律按附件处理,通过 isImage 来区分图片和非图片
            const imageType = ['image/png', 'image/jpg', 'image/gif', 'image/jpeg']
            if (imageType.includes(file.contentType)) {
                file.isImage = true
            } else {
                file.isImage = false
            }
        })
        res.render('index', { files: files })
    })
})

После завершения вышеуказанной ситуации, если мы посетим домашнюю страницу, она должна быть следующей

3.7 Загрузка одного файла

Здесь мы получаем доступ к интерфейсу /download/:filename через тег a.filename — это имя файла.Конечно, можно использовать и другие вещи, такие как _id.Когда вложение будет найдено, оно будет объединено в удобочитаемое пребывание и возвращено через конвейер, так что нажмите на название файла на внешнем интерфейсе, чтобы загрузить напрямую

app.get('/download/:filename', (req, res) => {
    gfs.files.findOne({ filename: req.params.filename }, (err, file) => {
        if (!file) {
            return res.status(404).json({
                err: '文件不存在!'
            })
        }
        const readstream = gfs.createReadStream(file.filename)
        readstream.pipe(res)
    })
})

3.8 Удаление одного файла

Здесь мы получаем доступ к интерфейсу /files/:id через тег a, идентификатор соответствует, нажмите кнопку удаления, он будет удален напрямую и перенаправлен на домашнюю страницу.

app.delete('/files/:id', (req, res) => {
    gfs.remove({ _id: req.params.id, root: 'upload' }, (err) => {
        if (err) {
            return res.status(404).json({
                err: '删除的文件不存在!'
            })
        }
        res.redirect('/')
    })
})

Поскольку мы использовали форму для отправки запросов, но форма формы не имеет метода запроса на удаление, поэтому мы использовалиmethod-overrideПлагины, конечно, не важно, используете ли вы Ajax, ведь наш проект быстрый, в основном зависит от эффекта и процесса.

4 Завершение цветка

Это просто закончилось, друзья, которые научились, могут попробовать более глубокие операции, поэтому мы можем использовать этот проект, чтобы сделать кровать-картинку или небольшой сетевой диск, или просто бросить его. Конечно, загрузка этого вложения также имеет определенные ограничения.Например, большой файл может загружаться дольше, поэтому нам нужно загружать его сегментами файла.Вы можете увидеть самородки.👉фрагментация файлаСлучай.

Напоследок спасибо за дегустацию.Если будет что-то новое и интересное, поделюсь еще раз.

Прочитайте хорошую книгу, что есть благородный человек говорит. - Гёте (я сказал)