Nodejs之MEAN栈开发(四)-- form验证及图片上传
zhezhongyun 2025-01-21 23:05 133 浏览
这一节增加推荐图书的提交和删除功能,来学习node的form提交以及node的图片上传功能。开始之前需要源码同学可以先在git上fork:https://github.com/stoneniqiu/ReadingClub
一、form验证
MVC的form验证有三个地方可以做,第一道关就是前端提交之前,第二道关就是在数据保存之前,也就是在controller中做验证,第三道关就是数据保存的时候,也就是如果提交的数据模型不符合实体定义的约束,数据是无法保存的,这是最后一道防线。第一道关主要是依赖于js或者jquery框架,比较常用的是jquery.validate.js。如果是Asp.net MVC 可以自动生成验证规则,这里就不细究了,网上有很多文章。第二层和各自的业务逻辑有关,也需要做一些必要验证,防止前端禁止JavaScript,而提交不合法数据,这里是要讲基于Mongoose的第三层验证。
1.回顾模型定义
我们先回顾一下之前用Mongoose定义的book模型:
var bookSchema = new mongoose.Schema({
title: { type: String, required: true },
rating: {
type: Number,
required: true,
min: 0,
max: 5
},
info: { type: String, required: true },
img: String,
tags: [String],
brief: { type: String, required: true },
ISBN: String,
});每个属性定义了类型和是否必须,还可以添加min,max,默认值等其他约束。如果提交的模型不满足这些约束,将不能保存成功。相当于Asp.net MVC中的DataAnnotations的作用。后面的form验证就基于此。
2.添加路由
我们需要增加4个路由规则,2个用于添加(一个get,一个post),一个用于删除,一个用于上传图片:
router.get('/book/create', homeController.bookcreateview);
router.post('/book/create', homeController.doBookCreate);
router.delete('/book/:id', homeController.delete);
router.post('/uploadImg', homeController.uploadImg);基于Express的路由,我们可以创建Restful的路由规则。路由位于app_server文件夹下。
3.添加控制器方法
home.bookcreateview:
module.exports.bookcreateview = function (req, res) {
res.render('bookCreate', { title: '新增推荐图书' });
};这里直接是一个get请求,所以直接用render去渲染视图,当然这个bookCreate视图接下来会创建。
doBookCreate:
module.exports.doBookCreate = function (req, res) {
var requestOptions, path, postdata;
path = "/api/book";
postdata = {
title: req.body.title,
info: req.body.info,
ISBN: req.body.ISBN,
brief: req.body.brief,
tags: req.body.tags,
img: req.body.img,
rating:req.body.rating,
};
requestOptions = {
url: apiOptions.server + path,
method: "POST",
json: postdata,
};
request(requestOptions, function (err, response, body) {
console.log("body.name", body.name, response.statusCode);
if (response.statusCode === 201) {
res.redirect("/detail/"+body._id);
}
else if (response.statusCode == 400 && body.name && body.name == "ValidationError") {
res.render('bookCreate', { title: '新增推荐图书', error:"val"});
}
else {
console.log("body.name",body.name);
info(res, response.statusCode);
}
});
};info:
function info (res, status) {
var title, content;
if (status === 404) {
title = "404, 页面没有找到";
content = "亲,页面飞走了...";
} else if (status === 500) {
title = "500, 内部错误";
content = "尴尬...,发生错误";
} else {
title = status + ", 有什么不对劲";
content = "某些地方可能有些错误";
}
res.status(status);
res.render('info', {
title : title,
content : content,
status: status,
});
};View Code
在上一节,我们创建了数据操作的api部分。代码的流程就是先从req中获取到前端传过来的数据,然后用request模块调用api,如果添加成功(状态码是201)就返回到detail页面,如果验证失败,就原路返回,并给出提示。如果错误,交给info方法去处理。
delete:
module.exports.delete = function (req, res) {
var requestOptions, path;
path = "/api/book/" + req.params.id;
requestOptions = {
url: apiOptions.server + path,
method: "delete",
json: {},
};
request(requestOptions, function (err, response, body) {
if (response.statusCode == 204) {
res.json(1);
}
else {
res.json(0);
}
});
};如果删除成功,返回的状态码是204,然后返回json(1)让前端去处理界面。
4.添加视图
1) 先需要在图书列表的右侧边栏增加一个按钮:
在books视图中修改:
.col-md-3
.userinfo
p stoneniqiu
a(href='/book/create').btn.btn-info 新增推荐当用户点击会跳转到/book/create页面
2)新增推荐页面:
extends layout
include _includes/rating
block content
.row
.col-md-12.page.bookdetail
h3 新增推荐书籍
.row
.col-xs-12.col-md-6
form.form-horizontal(action='',method="post",role="form")
- if (error == "val")
.alert.alert-danger(role="alert") All fields required, please try again
.form-group
label.control-label(for='title') 书名
input#name.form-control(name='title')
.form-group
label.control-label(for='info') 信息
input#name.form-control(name='info')
.form-group
label.control-label(for='ISBN') ISBN
input#name.form-control(name='ISBN')
.form-group
label.control-label(for='brief') 简介
input#name.form-control(name='brief')
.form-group
label.control-label(for='tags') 标签
input#name.form-control(name='tags')
.form-group
label.control-label(for='rating') 推荐指数
select#rating.form-control.input-sm(name="rating")
option 5
option 4
option 3
option 2
option 1
.form-group
p 上传图片
a.btn.btn-info(id="upload", name="upload") 上传图片
br
img(id='img')
.form-group
button.btn.btn-primary(type='submit') 提交
if语句的地方是用来显示错误提示;图片上传,稍后完整介绍;所以提交页面基本长成这样:
3)Mongoose验证
这个时候没有加前端验证,form可以直接提交。但是node打印出了错误日志,Book validation failed,验证失败。
这是Mongoose给我们返回的验证信息,这时界面上回显示一个提示信息:
这是因为在controller中的处理:
else if (response.statusCode == 400 && body.name && body.name == "ValidationError") {
res.render('bookCreate', { title: '新增推荐图书', error:"val"});
}以上说明了Mongoose会在数据保存的时候验证实体,如果实体不满足path规则,将不能保存。但至此有三个问题,第一个问题是提示信息不明确,当然我们可以遍历输出ValidatorError;第二个就是,验证错误之后,页面原来的数据没有了,需要再输入一遍,这个我们可以参考Asp.net MVC将模型数据填充到视图中可以解决;第三个问题就是页面前端还没有验证,form直接就可以提交了,这个可以通过简单的Jquery脚本就可以做到;这三点先不细究。继续往下看,如果规范输入,这个时候是可以提交的,提交之后在books页面可以看到:
4)删除
在标题的右侧增加了一个删除符号(books视图中):
.col-md-10
p
a(href="/Detail/#{book._id}")=book.title
span.close(data-id='#{book._id}') ×并添加脚本:
$(".close").click(function {
if (confirm("确定删除?")) {
var id = $(this).data("id");
var row = $(this).parents(".booklist");
$.ajax({
url: "/book/" + id,
method: "delete",
}).done(function(data) {
console.log(data);
row.fadeOut;
});
}
});脚本可以先位于layout视图下方:
script(src='/javascripts/books.js')
这样,删除完成之后会隐藏当前行。下面解决图片上传问题。
二、图片上传
前面我们在路由里面定义了一个uploadimg方法,现在实现它。一般都涉及两个部分,一个是前台图片的提交,一个是后端数据的处理。
1.uploadimg 方法实现
先需要安装formidable模块。
然后在Public文件下创建一个upload/temp文件夹
脚本:
var fs = require('fs');
var formidable = require('formidable');
module.exports.uploadImg = function (req, res) {
var form = new formidable.IncomingForm; //创建上传表单
form.encoding = 'utf-8'; //设置编辑
form.uploadDir = './../public/upload/temp/'; //设置上传目录
form.keepExtensions = true; //保留后缀
form.maxFieldsSize = 3 * 1024 * 1024; //文件大小
form.parse(req, function(err, fields, files) {
console.log(files);
if (err) {
console.log(err);
return res.json(0);
}
for (var key in files) {
console.log(files[key].path);
var extName = ''; //后缀名
switch (key.type) {
case 'image/pjpeg':
extName = 'jpg';
break;
case 'image/jpeg':
extName = 'jpg';
break;
case 'image/png':
case 'image/x-png':
default:
extName = 'png';
break;
}
var avatarName = (new Date).getTime + '.' + extName;
var newPath = form.uploadDir + avatarName;
fs.renameSync(files[key].path, newPath); //重命名
return res.json("/upload/temp/"+ avatarName);
}
});
};这个form会自动将文件保存到upLoadDir目录,并以upload_xxxx格式重新命名,所以最后使用fs模块对文件进行重命名。然后返回给前端。
2.前端
我喜欢用插件,前端我用的是plupload-2.1.8,拥有多种上传方式,比较方便。放置在Public文件下。在layout.jade中引用js:
script(src='/plupload-2.1.8/js/plupload.full.min.js') script(src='/javascripts/books.js')
而在bookCreate.jade视图中,修改如下:
a.btn.btn-info(id="upload", name="upload") 上传图片 br img(id='img') input#imgvalue(type='hidden',name='img',value='')
a标签用来触发上传,img用来预览,input用来存放路径。在books.js下增加以下代码:
var uploader = new plupload.Uploader({
runtimes: 'html5,flash,silverlight,html4',
browse_button: "upload",
url: '/uploadImg',
flash_swf_url: '/plupload-2.1.8/js/Moxie.swf',
silverlight_xap_url: '/plupload-2.1.8/js/Moxie.xap',
filters: {
max_file_size: "3mb",
mime_types: [
{ title: "Image files", extensions: "jpg,gif,png" },
{ title: "Zip files", extensions: "zip" }
]
},
init: {
PostInit: function {
},
FilesAdded: function (up, files) {
plupload.each(files, function (file) {
uploader.start;
});
},
UploadProgress: function (up, file) {
},
Error: function (up, err) {
}
}
});
uploader.init;
uploader.bind('FileUploaded', function (upldr, file, object) {
var data = JSON.parse(object.response);
console.log(data);
$("#img").attr("src", data);
$("#imgvalue").val(data);
});提交:
上传成功后跳转到detail页面。
至此,围绕form的提交这一节学习了Mongoose的数据验证,以及使用plupload上传,以及后端用formidable和fs模块处理图片。相对于Asp.net MVC而言,Asp.net MVC因为有自动化的form相对快捷一些。下一节将介绍Angular,作为MEAN中的A,该出场了。
相关推荐
- Python入门学习记录之一:变量_python怎么用变量
-
写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...
- python变量命名规则——来自小白的总结
-
python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...
- Python入门学习教程:第 2 章 变量与数据类型
-
2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...
- 绘制学术论文中的“三线表”具体指导
-
在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...
- Python基础语法知识--变量和数据类型
-
学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...
- 一文搞懂 Python 中的所有标点符号
-
反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...
- Python变量类型和运算符_python中变量的含义
-
别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...
- 从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序
-
在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...
- Python中下划线 ‘_’ 的用法,你知道几种
-
Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...
- 解锁Shell编程:变量_shell $变量
-
引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...
- 一文学会Python的变量命名规则!_python的变量命名有哪些要求
-
目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...
- 更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for
-
src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...
- C++第五课:变量的命名规则_c++中变量的命名规则
-
变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....
- Rust编程-核心篇-不安全编程_rust安全性
-
Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...
- 探秘 Python 内存管理:背后的神奇机制
-
在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- opacity 属性 (32)
- transition 属性 (33)
- 1-1. 变量声明 (31)
