我知道之前已经多次询问过,而且我已经阅读了几乎所有关于这个主题的内容,即:
https://stackoverflow.com/a/25022437/1031184
Uploading images using Node.js, Express, and Mongoose
这是迄今为止我发现的最好的。我的问题是他们仍然不是很清楚,关于这一点的网上文档很少,讨论似乎针对的是比我更先进的人。
所以,我真的很喜欢它,如果有人可以请走我,但如何使用Mongoose,Express& amp; AngularJS。我实际上正在使用MEAN fullstack。 (这个发生器准确 - 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。
正如我所说,我无法弄清楚如何将它们联系在一起。我甚至不确定我要做的是否也是正确的方法。
----------------------------------------------- --------------------------- \
更新
以下是我现在拥有的内容,我添加了一些详细说明我希望如何工作的评论,遗憾的是我仍然没有设法让这个工作,我甚至无法让图像开始上传,没关系上传到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;
};
}]);
server / 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);
}
服务器/配置/环境/ development.js
aws: {
key: 'XXXXXXXXXXXX',
secret: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
region: 'sydney',
bucketName: 'my-uploads'
}
答案 0 :(得分:11)
所有这些代码都直接来自一个项目,该项目在很大程度上依赖于大型文件上传和图像。绝对结帐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
答案 1 :(得分:2)
这是我使用 MEAN.JS 进行文件上传的方式。
<强>模型强>
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()
};
客户端控制器
Sub CreateArrayFromCSV()
Dim cn As ADODB.Connection, RS As ADODB.Recordset, strSQL As String
Dim rsArr As Variant, dataArr As Variant, yearArr As Variant
Dim i As Long, j As Long
strPath = "path"
Set cn = CreateObject("ADODB.Connection")
strcon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strPath & ";Extended Properties=""text;HDR=No;FMT=TabDelimited"";"
cn.Open strcon
<强> HTML 强>
ng-file-select 用于从客户端获取文件。
这对我来说很好。希望这会有所帮助。
注意:我使用 HTML 标记代替 jade 。使用 jade 时适用的更改。
答案 2 :(得分:1)
据我所知,你绑定了saveUserImage函数中的FileReader.onload()
方法,然后永远不会调用onload方法,因为函数永远不会被绑定,而是用户在编辑图像之前调用saveUserImage方法。之后,将不会选择任何图像,因为onload()
方法将不会执行。
尝试以这种方式编码客户端控制器
//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.-您的输入[type = file]是否显示?如果显示,请选择图像
2.-当所选图像发生变化时,您的输入是否正在调用onload? (应使用我的代码版本打印console.log)
3.-如果已被召唤。在发送之前,在onload方法中进行所需的操作(如果可能)
4.-此方法完成所需的更改后。通过onload方法生成的base64字符串,使用ng-model或您想要的信息通知您准备上传的对象中的变量。
到达这一点时,请记得检查:
由于可以使用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)
将为您提供一个base64字符串,可以充当图像的src。你不需要更多。这个base64是你可以在mongoose中保存的。然后,您可以使用ng-model通过“提交”按钮发送包含表单中base64的变量。
然后,在将处理表单的Express.js端点中,您将能够将base64字符串解码为文件,或者将base64直接保存在mongoose上(如果是,则不建议将数据存储在db中)因为mongoDB查询会很慢,所以要加载很多图像,或者需要加载大量图像。
希望你能用这些迹象来解决。如果您仍有疑问,请发表评论,我会尽力帮助
答案 3 :(得分:0)
我也是使用MEANJS的菜鸟,这就是我使用ng-flow + FileReader让它工作的方式:
HTML输入:
<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);
};
在服务器端,接收uploadImage值的模型上的变量只是字符串类型。
从服务器取回它不需要任何转换:
<img src={{result.picture}} class="pic-image" alt="Pic"/>
现在只需要了解如何处理大文件......