簡體   English   中英

使用MEAN.js上傳照片

[英]Uploading photographs using MEAN.js

我正在使用本教程該教程基於MEAN堆棧。 我想將用戶可以通過MongoDB上傳的照片存儲在服務器上。

包括: Angular指令上傳文件

創建-spot.client.view.html

<div data-ng-controller="SpotsCreateController">
    <form class="form-signin" data-ng-submit="create(picFile)" novalidate>
        <label>Upload an image</label>
        <input type="file" id="articleimage" ng-model="picFile" ng-file-select="" ng-file-change="generateThumb(picFile[0], $files)" multiple name="file" accept="image/*">
        <img ng-show="picFile[0].dataUrl != null" ng-src="{{picFile[0].dataUrl}}" class="img-thumbnail" height="50" width="100">
        <span class="progress" ng-show="picFile[0].progress >= 0">      
            <div style="width:{{picFile[0].progress}}%" ng-bind="picFile[0].progress + '%'" class="ng-binding"></div>
        </span> 
        <span ng-show="picFile[0].result">Upload Successful</span>

        <input type="submit" class="btn btn-lg btn-primary btn-block" ng-click="uploadPic(picFile)">

        <div data-ng-show="error">
            <strong data-ng-bind="error"></strong>
        </div>
    </form>
</div>

視圖spot.client.view.html

<div data-ng-controller="SpotsViewController">
    <section data-ng-init="findOne()">
        <img ng-src="data:image/jpeg;base64,{{spot.image}}" id="image-id" width="200" height="200"/>
    </section>
</div>

的application.js

var app = angular.module('newApp', ['ngAnimate', 'ngCookies', 'ngResource', 'ngRoute', 'ngSanitize', 'ngTouch', 'ui.bootstrap', 'users', 'spots']);

spots.create.client.controller.js

angular.module('spots').controller('SpotsCreateController', ['$scope', '$timeout', 'Authentication', 'Spots', '$location'
function($scope, $timeout, Authentication, Spots, $location) {
    $scope.authentication = Authentication;
    $scope.fileReaderSupported = window.FileReader !== null;

    $scope.create = function(picFile) {
        var spot = new Spots({
            title: this.title,
            description: this.description,
            image: null
        });
        spot.$save(function(response) {
            $location.path('spots/' + response._id);
        }, function(errorResponse) {
            $scope.error = errorResponse.data.message;
        });
    };

    $scope.doTimeout = function(file) {
        $timeout( function() {
            var fileReader = new FileReader();
            fileReader.readAsDataURL(file);
            fileReader.onload = function(e) {
                $timeout(function() {
                    file.dataUrl = e.target.result;
                });
            };
        });
    };
    $scope.generateThumb = function(file) {
        if (file) {
            if ($scope.fileReaderSupported && file.type.indexOf('image') > -1) {
                $scope.doTimeout(file);
            }
        }
    };

spot.server.model.js

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var SpotSchema = new Schema({
    ...
    image: {
        type: String,
        default: '',
        required: false
    }
});

mongoose.model('Spot', SpotSchema);

spots.server.routes.js

var multiparty = require('connect-multiparty'),
    multipartyMiddleware = multiparty();

module.exports = function(app) {
    app.route('/api/spots')
        .get(spots.list)
        .post(users.requiresLogin, multipartyMiddleware, spots.create);

    app.route('/api/spots/:spotId')
        .get(spots.read)
        .put(users.requiresLogin, spots.hasAuthorization, spots.update)
        .delete(users.requiresLogin, spots.hasAuthorization, spots.delete);

    app.param('spotId', spots.spotByID);
};

spots.server.controller.js

var mongoose = require('mongoose'),
    fs = require('fs'),
    Spot = mongoose.model('Spot');

exports.create = function(req, res) {
    if (req.files.file) {
        var file = req.files.file;
    }

    var spot = new Spot(req.body);
    spot.creator = req.user;

    fs.readFile(file.path, function (err,original_data) {
        if (err) {
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        }
        var base64Image = original_data.toString('base64');
        fs.unlink(file.path, function (err) {
            if (err) {
                console.log('failed to delete ' + file.path);
            } else {
                console.log('successfully deleted ' + file.path);
            }
        });
        spot.image = base64Image;
        spot.save(function(err) {
            if (err) {
                return res.status(400).send({
                    message: getErrorMessage(err)
                });
            } else {
                res.json(spot);
            }
        });
    });
};

我做錯了什么? 請考慮我想限制文件大小,並且我認為使用base64是一個好的開始。 問題是照片未存儲在數據庫中,因為控制器無法與其他照片一起使用。

您遇到的問題到底是什么?錯在哪一步?

對於Express后端應用程序,我通常使用multer中間件來處理文件上傳。 另外,我創建了單獨的路由/控制器來處理文件,而不是在保存父對象的同時嘗試處理它們。 這使我可以很好地分離邏輯,而不必擔心文件上傳失敗時不會保存父對象。 您可以使用ng-file-upload的JS API在Angular中進行處理。

Express中的路線示例(此處有一個帶有“徽標”圖像的“俱樂部”):

router.post(
  '/logo',
  ensureAuthenticated, ensureAdmin,
  logoCtrl.upload,
  logoCtrl.save
);
router.get(
  '/:clubId/logo.*',
  logoCtrl.stream
);

控制器方法示例:

let multer = require('multer');
module.exports = {

  /**
   * Upload logo
   */
  save(req, res, next) {

    //Get club and file
    let club = req.user.club;
    let file = req.file;

    //Update
    club.logo = {
      data: file.buffer,
      mimeType: file.mimetype
    };

    //Save
    club.save()
      .then(() => {
        res.end();
      })
      .catch(next);
  },

  /**
   * Stream logo
   */
  stream(req, res, next) {
    let club = req.club;
    res.contentType(club.logo.mimeType);
    res.send(club.logo.data);
  },

  /**
   * Upload middleware
   */
  upload(req, res, next) {

    //Create upload middleware
    let upload = multer({
      storage: multer.memoryStorage(),
      limits: {
        fileSize: 50000000
      }
    }).single('logo');

    //Use middleware
    upload(req, res, next);
  }
};

因此,如您所見,使用multer非常簡單,您真正需要的只是一種上傳徽標的途徑,它具有兩種控制器方法,一種用於注冊multer中間件並處理文件,另一種用於將其保存到MongoDB(在這種情況下,請附加到俱樂部)。

只需確保ng-file-upload使用與multer期望的相同的字段名稱來上傳文件。 在上面的示例中為“徽標”。 如果不確定,請在請求中簽入客戶端應用程序發送到服務器的內容,並確保服務器應用程序使用相同的字段名稱。

讓我知道您是否還有其他麻煩。

您可以使用formidablegridfs-stream

//controller
var mongoose = require('mongoose'),
  fs = require('fs'),
  Spot = mongoose.model('Spot');

exports.create = function(req, res) {
  handleRequest(req, function(err, spot) {
    if(err) {
      return res.status(400).send({
        message: getErrorMessage(err)
      });
    }

    res.json(spot);

  });
};

function handleRequest(req) {

  var spot = new Spot(req.body);
  spot.creator = req.user;

  var formidable = require('formidable');

  var form = new formidable.IncomingForm();

  form.parse(req, function(err, fields, files) {
    if (err) {
      return done(err);
    }
    var file = files.qqfile;
    if (file && file.name && file.name.trim !== '') {
      if (file.size > 5000000) {
        message = 'file is too large';
      }
      if (!file.type) {
        message = 'file is not an image';
      }
      if (file.type.indexOf('image/') !== 0) {
        message = 'file is not an image type';
      }
    }
    if (message) {
      logger.info('Uploading failed', file, message);
      return done(message);
    }

    uploadFile(mongoose.connection, 'Pictures', files.qqfile, require('uuid').v1(), function(err) {
      if (err) {
        return done(err);
      }
      if (!data) return done(false, null);

      if (typeof data === 'string') {
        data = JSON.parse(data);
      }
      logger.info('[PHOTOS]', 'Uploaded', data.filename);
      photo = {
        unique_id: token,
        name: file.name,
        contentType: file.type
      };

      spot.photos = spot.photos || [];
      spot.photos.push(photo);
      spot.markModified('photos');
      spot.save(done);

    });
  });
}

function uploadFile(DB, className, data, token, callback) {
  var grid = require('gridfs-stream');
  var gfs = grid(DB.db, mongoose.mongo);

  var writestream = gfs.createWriteStream({
    filename: token,
    root: className
  });
  writestream.on('close', function (file) {
    return callback(null, file);
  });

  if (data.path) {
    var fs = require('fs');
    if (!fs.existsSync(data.path)) {
      return callback(false);
    }
    var pipe = false;
    if (data.pipe) {
      pipe = data.pipe;
    } else {
      var fs = require('fs');
      if (!fs.existsSync(data.path)) {
        return callback(false);
      }
      var rs = fs.createReadStream(data.path);
      pipe = rs.pipe.bind(rs);
    }
    return pipe(writestream);
  } else {
    logger.error('[PHOTO] no path', data);
  }
  callback(false);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM