使用Mongoose,Express和AngularJS上传图片

我知道这个问题以前已经被问过很多次了,而且我几乎可以读到关于这个问题的所有东西,比如:

https://stackoverflow.com/a/25022437/1031184

使用Node.js,Express和Mongoose上传图像

这些是迄今为止我发现的最好的。 我的问题是,他们还不是很清楚,关于这方面的文档很less,而且讨论似乎针对那些比我更先进的人。

所以,如果有人可以请我走,但如何使用Mongoose,Express&AngularJS上传图片,我真的会喜欢它。 我实际上正在使用平均满量程。 (这个生成器是精确的 – https://github.com/DaftMonk/generator-angular-fullstack )

AddController:

'use strict'; angular.module('lumicaApp') .controller('ProjectAddCtrl', ['$scope', '$location', '$log', 'projectsModel', 'users', 'types', function ($scope, $location, $log, projectsModel, users, types) { $scope.dismiss = function () { $scope.$dismiss(); }; $scope.users = users; $scope.types = types; $scope.project = { name: null, type: null, images: { thumbnail: null // I want to add the uploaded images _id here to reference with mongoose populate. }, users: null }; $scope.save = function () { $log.info($scope.project); projectsModel.post($scope.project).then(function (project) { $scope.$dismiss(); }); } }]); 

我想将图像ID引用添加到project.images.thumbnail但我想要使用以下架构存储图像对象中的所有信息:

 'use strict'; var mongoose = require('mongoose'), Schema = mongoose.Schema; var ImageSchema = new Schema({ fileName: String, url: String, contentType: String, size: String, dimensions: String }); module.exports = mongoose.model('Image', ImageSchema); 

我还添加了以下的https://github.com/nervgh/angular-file-upload到我的bower软件包。

正如我所说,我无法弄清楚如何将它们结合在一起。 而且我甚至不确定我想要做的是否正确的方法。

————————————————– ———————— \

更新:

这里是我现在有,我已经添加了一些意见,详细说明我希望它的工作,不幸的是我还没有设法得到这个工作,我甚至无法得到形象开始上传,没关系上传到S3 。 对不起,是一个痛苦,但我只是觉得这特别令人困惑,这让我感到惊讶。

客户端/应用/人/添加/ add.controller.js

 'use strict'; angular.module('lumicaApp') .controller('AddPersonCtrl', ['$scope', '$http', '$location', '$window', '$log', 'Auth', 'FileUploader', 'projects', 'usersModel', function ($scope, $http, $location, $window, $log, Auth, FileUploader, projects, usersModel) { $scope.dismiss = function () { $scope.$dismiss(); }; $scope.newResource = {}; // Upload Profile Image $scope.onUploadSelect = function($files) { $scope.newResource.newUploadName = $files[0].name; $http .post('/api/uploads', { uploadName: newResource.newUploadName, upload: newResource.newUpload }) .success(function(data) { newResource.upload = data; // To be saved later }); }; $log.info($scope.newResource); //Get Projects List $scope.projects = projects; //Register New User $scope.user = {}; $scope.errors = {}; $scope.register = function(form) { $scope.submitted = true; if(form.$valid) { Auth.createUser({ firstName: $scope.user.firstName, lastName: $scope.user.lastName, username: $scope.user.username, profileImage: $scope.user.profileImage, // I want to add the _id reference for the image here to I can populate it with 'ImageSchema' using mongoose to get the image details(Name, URL, FileSize, ContentType, ETC) assigned: { teams: null, projects: $scope.user.assigned.projects }, email: $scope.user.email, password: $scope.user.password }) .then( function() { // Account created, redirect to home //$location.path('/'); $scope.$dismiss(); }) .catch( function(err) { err = err.data; $scope.errors = {}; // Update validity of form fields that match the mongoose errors angular.forEach(err.errors, function(error, field) { form[field].$setValidity('mongoose', false); $scope.errors[field] = error.message; }); }); } }; $scope.loginOauth = function(provider) { $window.location.href = '/auth/' + provider; }; }]); 

服务器/ api / image / image.model.js我想在这里存储所有的图像信息,并使用它来在人控制器中填充profileImage

 'use strict'; var mongoose = require('mongoose'), Schema = mongoose.Schema; var ImageSchema = new Schema({ fileName: String, url: String, // Should store the URL of image on S3. contentType: String, size: String, dimensions: String }); module.exports = mongoose.model('Image', ImageSchema); 

客户端/应用/人/添加/ add.jade

 .modal-header h3.modal-title Add {{ title }} .modal-body form(id="add-user" name='form', ng-submit='register(form)', novalidate='') .form-group(ng-class='{ "has-success": form.firstName.$valid && submitted,\ "has-error": form.firstName.$invalid && submitted }') label First Name input.form-control(type='text', name='firstName', ng-model='user.firstName', required='') p.help-block(ng-show='form.firstName.$error.required && submitted') | First name is required .form-group(ng-class='{ "has-success": form.lastName.$valid && submitted,\ "has-error": form.lastName.$invalid && submitted }') label Last Name input.form-control(type='text', name='lastName', ng-model='user.lastName', required='') p.help-block(ng-show='form.lastName.$error.required && submitted') | Last name is required .form-group(ng-class='{ "has-success": form.username.$valid && submitted,\ "has-error": form.username.$invalid && submitted }') label Username input.form-control(type='text', name='username', ng-model='user.username', required='') p.help-block(ng-show='form.username.$error.required && submitted') | Last name is required // Upload Profile Picture Here .form-group label Profile Image input(type="file" ng-file-select="onUploadSelect($files)" ng-model="newResource.newUpload") .form-group(ng-class='{ "has-success": form.email.$valid && submitted,\ "has-error": form.email.$invalid && submitted }') label Email input.form-control(type='email', name='email', ng-model='user.email', required='', mongoose-error='') p.help-block(ng-show='form.email.$error.email && submitted') | Doesn't look like a valid email. p.help-block(ng-show='form.email.$error.required && submitted') | What's your email address? p.help-block(ng-show='form.email.$error.mongoose') | {{ errors.email }} .form-group(ng-class='{ "has-success": form.password.$valid && submitted,\ "has-error": form.password.$invalid && submitted }') label Password input.form-control(type='password', name='password', ng-model='user.password', ng-minlength='3', required='', mongoose-error='') p.help-block(ng-show='(form.password.$error.minlength || form.password.$error.required) && submitted') | Password must be at least 3 characters. p.help-block(ng-show='form.password.$error.mongoose') | {{ errors.password }} .form-group label Assign Project(s) br select(multiple ng-options="project._id as project.name for project in projects" ng-model="user.assigned.projects") button.btn.btn-primary(ng-submit='register(form)') Save pre(ng-bind="user | json") .modal-footer button.btn.btn-primary(type="submit" form="add-user") Save button.btn.btn-warning(ng-click='dismiss()') Cancel 

服务器/ API /上传/ index.js

 'use strict'; var express = require('express'); var controller = require('./upload.controller'); var router = express.Router(); //router.get('/', controller.index); //router.get('/:id', controller.show); router.post('/', controller.create); //router.put('/:id', controller.update); //router.patch('/:id', controller.update); //router.delete('/:id', controller.destroy); module.exports = router; 

服务器/ API /上传/ upload.controller.js

 'use strict'; var _ = require('lodash'); //var Upload = require('./upload.model'); var aws = require('aws-sdk'); var config = require('../../config/environment'); var randomString = require('../../components/randomString'); // Creates a new upload in the DB. exports.create = function(req, res) { var s3 = new aws.S3(); var folder = randomString.generate(20); // I guess I do this because when the user downloads the file it will have the original file name. var matches = req.body.upload.match(/data:([A-Za-z-+\/].+);base64,(.+)/); if (matches === null || matches.length !== 3) { return handleError(res, 'Invalid input string'); } var uploadBody = new Buffer(matches[2], 'base64'); var params = { Bucket: config.aws.bucketName, Key: folder + '/' + req.body.uploadName, Body: uploadBody, ACL:'public-read' }; s3.putObject(params, function(err, data) { if (err) console.log(err) else { console.log("Successfully uploaded data to my-uploads/" + folder + '/' + req.body.uploadName); return res.json({ name: req.body.uploadName, bucket: config.aws.bucketName, key: folder }); } }); }; function handleError(res, err) { return res.send(500, err); } 

服务器/configuration/环境/ development.js

 aws: { key: 'XXXXXXXXXXXX', secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', region: 'sydney', bucketName: 'my-uploads' } 

所有这些代码都是直接从一个很大程度上依赖于此的大型file upload和图像的项目。 绝对结帐https://github.com/nervgh/angular-file-upload

在我看来某处:

 <div class="form-group"> <label>File Upload</label> <input type="file" ng-file-select="onUploadSelect($files)" ng-model="newResource.newUpload"> </div> 

然后使用模块angularFileUpload在我的控制器中:

 $scope.onUploadSelect = function($files) { $scope.newResource.newUploadName = $files[0].name; }; 

https://github.com/nervgh/angular-file-upload

当用户点击上传时,在我发送要上传的文件的地方执行:

 $http .post('/api/uploads', { uploadName: newResource.newUploadName, upload: newResource.newUpload }) .success(function(data) { newResource.upload = data; // To be saved later }); 

这个请求被发送到一个看起来像这样的控制器:

 'use strict'; var _ = require('lodash'); var aws = require('aws-sdk'); var config = require('../../config/environment'); var randomString = require('../../components/randomString'); // Creates a new upload in the DB. exports.create = function(req, res) { var s3 = new aws.S3(); var folder = randomString.generate(20); // I guess I do this because when the user downloads the file it will have the original file name. var matches = req.body.upload.match(/data:([A-Za-z-+\/].+);base64,(.+)/); if (matches === null || matches.length !== 3) { return handleError(res, 'Invalid input string'); } var uploadBody = new Buffer(matches[2], 'base64'); var params = { Bucket: config.aws.bucketName, Key: folder + '/' + req.body.uploadName, Body: uploadBody, ACL:'public-read' }; s3.putObject(params, function(err, data) { if (err) console.log(err) else { console.log("Successfully uploaded data to csk3-uploads/" + folder + '/' + req.body.uploadName); return res.json({ name: req.body.uploadName, bucket: config.aws.bucketName, key: folder }); } }); }; function handleError(res, err) { return res.send(500, err); } 

服务器/组件/ randomString / index.js

 'use strict'; module.exports.generate = function(textLength) { textLength = textLength || 10; var text = ''; var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; for(var i = 0; i < textLength; i++) { text += possible.charAt(Math.floor(Math.random() * possible.length)); } return text; }; 

在这里输入图像描述

server/config/environment/development.js

在这里输入图像描述

server/api/upload/upload.controller.js

在这里输入图像描述

这是我使用MEAN.JS进行file upload的方式。

模型

 var UserSchema = new mongoose.Schema({ name:{type:String,required:true}, photo:Buffer // Image }); 

服务器控制器

 var userPicture = function(req,res){ // Stores Picture for a user matching the ID. user.findById(req.param('id'), function (err, user) { console.log(req.files) // File from Client if(req.files.file){ // If the Image exists var fs = require('node-fs'); fs.readFile(req.files.file.path, function (dataErr, data) { if(data) { user.photo =''; user.photo = data; // Assigns the image to the path. user.save(function (saveerr, saveuser) { if (saveerr) { throw saveerr; } res.json(HttpStatus.OK, saveuser); }); } }); return } res.json(HttpStatus.BAD_REQUEST,{error:"Error in file upload"}); }); }; 

客户控制器

 $scope.saveuserImage = function(){ $scope.upload = $upload.upload({ // Using $upload url: '/user/'+$stateParams.id+'/userImage', // Direct Server Call. method:'put', data:'', // Where the image is going to be set. file: $scope.file }).progress(function (evt) {}) .success(function () { var logo = new FileReader(); // FileReader. $scope.onAttachmentSelect = function(file){ logo.onload = function (e) { $scope.image = e.target.result; // Assigns the image on the $scope variable. $scope.logoName = file[0].name; // Assigns the file name. $scope.$apply(); }; logo.readAsDataURL(file[0]); $scope.file = file[0]; $scope.getFileData = file[0].name }; location.reload(); $scope.file = ""; $scope.hideUpload = 'true' }); $scope.getFileData = ''; // location.reload() }; 

HTML

ng-file-select用于从客户端获取文件。

这对我来说很好。 希望这可以帮助。

注意 :我使用了HTML标签而不是 。 使用玉石时适用的变化。

据我猜测,你绑定了SaveUserImage函数中的FileReader.onload()方法,那么onload方法将永远不会被调用,因为函数不会被绑定,而是用户在编辑图像之前调用saveUserImage方法。 之后,由于onload()方法将不会执行,因此不会select图像。

尝试用这种方法编码客户端控制器

 //This goes outside your method and will handle the file selection.This must be executed when your `input(type=file)` is created. Then we will use ng-init to bind it. $scope.onAttachmentSelect = function(){ var logo = new FileReader(); // FileReader. logo.onload = function (event) { console.log("THE IMAGE HAS LOADED"); var file = event.currentTarget.files[0] console.log("FILENAME:"+file.name); $scope.image = file; $scope.logoName = file.name; // Assigns the file name. $scope.$apply(); //Call save from here $scope.saveuserImage(); }; logo.readAsDataURL(file[0]); $scope.file = file[0]; $scope.getFileData = file[0].name reader.readAsDataURL(file); }; //The save method is called from the onload function (when you add a new file) $scope.saveuserImage = function(){ console.log("STARGING UPLOAD"); $scope.upload = $upload.upload({ // Using $upload url: '/user/'+$stateParams.id+'/userImage', method:'put' data:, $scope.image file: $scope.file }).progress(function (evt) {}) .success(function () { location.reload(); $scope.file = ""; $scope.hideUpload = 'true' }); $scope.getFileData = ''; // location.reload() }; 

HTML。

 //There is the ng-init call to binding function onAttachmentSelect <div class="form-group"> <label>File Upload</label> <input type="file" ng-init="onAttachmentSelect" ng-model="newResource.newUpload"> </div> 

希望这个线索可以帮助你

编辑*

将尝试解释你不同的步骤,你必须遵循检查你的代码:

1.-您的input[type = file]是否显示? 如果显示,请select一个图像

2.-当您select的图像改变时,您的input是否调用onload? (一个console.log应该用我的代码版本打印)

3.如果已被调用。 在发送前,在onload方法内进行所需的操作(如果可能的话)

4.-当这个方法完成了所需的改变。 通过ng-model或者你想要的,你准备上传的对象中的一个variables,在onload方法中生成base64string。

到达这一点时,请记住检查:

由于非常大的图像可以通过使用base64的json发送,因此记住在Express.js中更改最小的json大小以防止被拒绝是非常重要的。 这是完成的,例如在你的server / app.js中是这样的:

 var bodyParser = require('body-parser'); app.use(bodyParser.json({limit: '50mb'})); app.use(bodyParser.urlencoded({limit: '50mb'})); 

还要记住方法reader.readAsDataURL(file)会给你一个base64string,可以作为图像的src。 你不需要比这更多。 这base64是你可以保存在mongoose。 然后,可以使用ng-model通过“submit”button发送一个包含base64的variables。

然后,在将处理您的表单的Express.js端点中,您将能够将base64string解码为一个文件,或者将base64直接保存在mongoose上(在db中存储图像不是太多,build议如果大量图像正在被加载,或大的期望,因为mongoDB查询将非常慢)。

希望你能解决这些迹象。 如果您还有疑问,请发表评论,我会尽力帮助

我也是使用MEANJS的noob,这是我使用ng-flow + FileReader的工作原理:

HTMLinput:

 <div flow-init flow-files-added="processFiles($files)" flow-files-submitted="$flow.upload()" test-chunks="false"> <!-- flow-file-error="someHandlerMethod( $file, $message, $flow )" ! need to implement--> <div class="drop" flow-drop ng-class="dropClass"> <span class="btn btn-default" flow-btn>Upload File</span> <span class="btn btn-default" flow-btn flow-directory ng-show="$flow.supportDirectory">Upload Folder</span> <b>OR</b> Drag And Drop your file here </div> 

控制器:

  $scope.uploadedImage = 0; // PREPARE FILE FOR UPLOAD $scope.processFiles = function(flow){ var reader = new FileReader(); reader.onload = function(event) { $scope.uploadedImage = event.target.result; }; reader.onerror = function(event) { console.error('File could not be read! Code ' + event.target.error.code); }; reader.readAsDataURL(flow[0].file); }; 

而在服务器端,接收uploadedImage值的模型上的variables只是stringtypes。

从服务器取回不需要任何转换:

 <img src={{result.picture}} class="pic-image" alt="Pic"/> 

现在只需要找出如何处理大文件…