本节增加了提交和删除推荐书籍的功能,学习node的表单提交和node的图片上传功能。开始前需要源代码的同学可以在git上叉:https://github.com/stoneniqiu/ReadingClub.
第一,形式验证
做MVC的表单验证有三个地方。第一关是前端提交之前,第二关是数据保存之前,也就是在控制器里做验证,第二关是数据保存的时候,也就是如果提交的数据模型不满足实体定义的约束,就不能保存数据,这是最后一道防线。第一遍主要依靠js或者jquery框架,常用jquery.validate.js。如果Asp.net MVC能自动生成验证规则,这里就不赘述了。网上有很多文章。第二层和他们的业务逻辑有关,需要做一些必要的验证,防止前端禁止JaScript,提交非法数据。这里要说的是基于Mongoose的第三层验证。
1.回顾模型定义
我们来回顾一下之前Mongoose定义的图书模型:
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 }, IN: String,});
每个属性定义了类型和是否必须,还可以添加min,max,默认值等其他约束。如果提交的模型不满足这些约束,将不能保存成功。相当于Asp.net MVC中的DataAnnotations的作用。后面的form验证就基于此。新猫鼬。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 },IN: String,});每个属性定义了类型和是否必要,还可以添加其他约束,如最小值、最大值和默认值。如果提交的模型不满足这些约束,它将不会被成功保存。相当于Asp.net MVC中DataAnnotations的作用。下面的表单验证就是基于此。
2.添加路由
我们需要添加四个路由规则,两个用于添加(一个get,一个post),一个用于删除,一个用于上传图片:
router.get(‘/book/create ‘,home controller . bookcreateview);router.post(‘/book/create ‘,home controller . dobook create);router.delete(‘/book/:id ‘,home controller . delete);router.post(‘/uploadImg ‘,home controller . upload img);基于快速路由,我们可以创建Restful路由规则。路线位于app_server文件夹中。
3.添加控制器方法
home.bookcreateview:
module . exports . bookcreateview = function(req,res) {res.render (‘bookcreate ‘,{title:’新推荐书籍’ });};这是一个直接的get请求,所以直接呈现视图。当然,接下来将创建这个bookCreate视图。
doBookCreate:
module.exports.doBookCreate = function (req, res) { var requestOptions, path, postdata; path = “/api/book”; postdata = { title: req.body.title, info: req.body.info, IN: req.body.IN, 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:module . exports . dobook create = function(req,res) { var requestOptions,path,postdatapath = “/API/book “;postdata = { title: req.body.title,info: req.body.info,IN: req.body.IN,brief: req.body.brief,tags: req.body.tags,img: req.body.img,rating:req.body.rating,};request options = { URL:API options . server+path,method: “POST “,json: postdata,};request(requestOptions,function (err,response,body) { console.log(“body.name “,body.name,response . status code);if(response . status code = = = 201){ RES . redirect(“/detail/”+body。_ id);} else if(response . status code = = 400 & amp;& ampbody.name & amp& ampbody . name = = ” validation error “){ RES . render(‘ book create ‘,{title:’新推荐图书’,错误:” val ” });} else { console.log(“body.name “,正文.名称);info(res,response . status code);} });};信息:
函数信息(res,status) { var title,contentIf (status === 404) {title = “404,找不到页面”;Content = “亲爱的,页面飞走了…”;} else if(status = = = 500){ title = ” 500,内部错误”;Content = “尴尬…出现错误”;} else {title = status+”,怎么了”;Content = “有些地方可能有些错误”;} res.status(状态);res.render(‘info ‘,{ title:标题,content:内容,status:状态,});};查看代码
在上一节中,我们创建了数据操作的api部分。代码的流程是先从req中获取前端的数据,然后用请求模块调用api。如果添加成功(状态码为201),则返回详情页,如果验证失败,则返回原路并给出提示。如果是错的,就交给info方法处理。
删除:
module . exports . delete = function(req,res) { var requestOptions,pathpath = “/API/book/”+req . params . id;request options = { URL:API options . server+path,方法:“delete”,json: {},};request(requestOptions,function (err,response,body){ if(response . status code = = 204){ RES . JSON(1);} else { RES . JSON(0);} });};如果删除成功,返回的状态码是204,然后返回json(1)供前端处理接口。
4.添加视图
1)首先,您需要在图书列表右侧的侧边栏中添加一个按钮:
在图书视图中修改:
。col-MD-3。userinfo pstone ni Qiu a(href = ‘/book/create ‘)。BTN。BTN信息新推荐点击后会跳转到/预订/创建页面。
2)添加推荐页面:
extends layoutinclude _includes/ratingblock 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=’IN’) IN input#name.form-control(name=’IN’) .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-(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语句的地方是用来显示错误提示;图片上传,稍后完整介绍;所以提交页面基本长成这样:extends layout include _ includes/ratingblockcontent . row . col-MD-12 . page . book detail H3添加推荐书籍。row . col-xs-12 . col-MD-6 form . form-horizontal(action = ‘ ‘,method=”post “,role = ” form “)-if(error = = ” val “)alert . alert-danger(role = ” alert “)所有字段均为必填项,请重试。表单-组标签。Control-label (for =’ title ‘)标题输入# name。表单控件(name =’ title ‘)。表单-组标签。控件标签(for =’ info ‘)。信息输入#名称。表单控件(name =’ info ‘)。表单组标签。控制标签(for =’ IN’) IN输入# name。表单控件(name =’ IN ‘)。。表单组标签。输入# name的控制标签(for =’ brief ‘)介绍。表单控件(name =’ brief ‘)。表单组标签。control-label (for =’ tags ‘)标签输入# Name。表单控件(name =’ tags ‘)。表单组标签。控制标签(for =’ rating ‘)推荐指标选择# rating。形式控制。input- (name =’ rating ‘)。选项5选项4选项3选项2选项1.form-group p上传一张图片a.btn.btn-info (ID = “upload “,name = “upload “)上传一张图片Brimg (ID =’ img ‘)。form-group button . BTN-primary(type = ‘ submit ‘)并提交它。上传图片,后面完整介绍;所以提交页面基本上是这样的:
3)猫鼬验证
此时没有前端验证,可以直接提交表单。但是,node打印出了错误日志,图书验证失败,验证失败。
这是猫鼬返回的验证信息。这时,界面上显示出上次的提示信息:
这是因为控制器中的处理:
else if(response . status code = = 400 & amp;& ampbody.name & amp& ampbody . name = = ” validation error “){ RES . render(‘ book create ‘,{title:’新推荐图书’,错误:” val ” });}以上说明Mongoose在保存数据时会验证实体。如果实体不符合路径规则,则不会被保存。但是到目前为止有三个问题。第一个问题是提示信息不明确。当然,我们可以遍历输出ValidatorError。第二种是验证错误后,页面的原始数据没有了,需要重新输入。这可以通过参考Asp.net MVC将模型数据填充到视图中来解决;第三个问题是页面前端没有经过验证,可以直接提交表单,通过简单的Jquery脚本就可以完成;这三点我们就不深究了。继续往下看,如果输入规范,此时可以提交。提交后,您可以在图书页面上看到:
4)删除
在标题右侧添加了删除符号(在图书视图中):
。col-MD-10 p a(href = “/Detail/# { book。_ id } “)= book . title span . close(data-id = ‘ # { book。_ id } ‘)& amp;时代;并添加一个脚本:
$ (“.关闭”)。点击(function {if (confirm(“确定要删除吗?))){ var id = $(这个)。数据(“id”);var row = $(this)。父母(“。书单”);$.ajax({ url: “/book/” + id,method: “delete “,})。done(函数(数据){ console.log(数据);row.fadeOut});}});脚本可以首先位于布局视图下方:
script(src = ‘/JaScript/books . js ‘),以便删除后隐藏当前行。先解决图片上传的问题吧。
二、图片上传
前面我们在路由里面定义了一个uploadimg方法,现在实现它。一般都涉及两个部分,一个是前台图片的提交,一个是后端数据的处理。之前,我们在路由中定义了一个uploadimg方法,现在我们实现它。一般涉及两部分,一是前台图片的提交,二是后台数据的处理。
1.uploadimg 方法实现
你需要先安装强大的模块。
然后在公共文件下创建一个upload/temp文件夹。
脚本:
var fs = require(‘ fs ‘);var calendar = require(‘ calendar ‘);module . exports . upload img = function(req,RES){ var form = new harvardable。收入形式;//创建上传表单form . encoding = ‘ utf-8 ‘;//设置编辑表单。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].路径);var extName =“”;//后缀开关(key . type){ case ‘ image/pj peg ‘:extname = ‘ jpg ‘;打破;case“image/JPEG”:extName =“jpg”;打破;case ‘ image/png ‘:case ‘ image/x-png ‘:默认值:extName = ‘ png打破;} var atarName =(新日期)。getTime +’ . ‘+extName;var new path = form . uploaddir+atar name;fs.renameSync(files[key])。path,new path);//重命名returnres . JSON(“/upload/temp/”+头像名);} });};该表单会自动将文件保存到upLoadDir目录,并以upload_xxxx的格式重命名,所以最后会使用fs模块对文件进行重命名。然后返回到前端。
2.前端
我喜欢用插件。前端我用的是plupload-2.1.8,上传方式多样,比较方便。把它放在公共档案下。在layout.jade中引用js:
script(src = ‘/plo upload-2 . 1 . 8/js/plo upload . full . min . js ‘)script(src = ‘/JaScript s/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下增加以下代码:A.btn.btn-info (ID = “upload “,name = “upload “)上传图片BRIMG(ID = ‘ img ‘)input # img value(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);});
提交:var uploader = new plupload。上传器({运行时:’ 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 ‘,过滤器:{ max_file_size: “3mb “,mime_types: [ { title: “Image files “,扩展名:” jpg,gif,png” },{ title});},UploadProgress: function (up,file) { },Error: function (up,err){ } });uploader.inituploader.bind(‘FileUploaded ‘,function (upldr,file,object){ var data = JSON . parse(object . response);console.log(数据);$(“#img “)。attr(“src “,数据);$(“#imgvalue “)。val(数据);});提交:
上传成功后跳转到详情页。
至此,我们已经学会了Mongoose围绕表单提交的数据校验,以及用plupload上传,后端用calendar和fs模块处理图片。与Asp.net MVC相比,Asp.net MVC速度更快,因为它的自动化形式。下一节将介绍Angular,意思是该上场了。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。