我正在使用基于MEAN堆栈的this tutorial。 我想存储用户可以在服务器上使用MongoDB上传的照片。
包括:Angular directive to upload files
创建-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
是一个好的开始。问题是照片没有存储在数据库中,因为控制器不能与其余部分一起使用。
答案 0 :(得分:2)
您遇到的问题究竟是什么,以及出现了什么问题?
对于Express后端应用程序,我通常使用multer中间件来处理文件上传。此外,我创建了单独的路由/控制器来处理文件,而不是在我保存父对象的同时尝试处理它们。这允许我很好地分离逻辑,而不用担心在文件上载失败时没有保存父对象。你可以使用JS API进行ng-file-upload来处理Angular。
Express中的示例路线(我们有一个&#34;俱乐部&#34;带有&#34;徽标&#34;图像在这里):
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所期望的文件。在上面的示例中,&#34; logo&#34;。如果您不确定,请检查您的客户端应用程序发送给服务器的请求,并确保服务器应用程序需要相同的字段名称。
如果您有进一步的麻烦,请告诉我。
答案 1 :(得分:1)
您可以使用formidable
和gridfs-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);
}