mean技术栈 linux,“MEAN”技术栈开发web应用

48304ba5e6f9fe08f3fa1abda7d326ab.png

var express = require('express');

var app = express();

app.listen(3000);

var _rootDir = __dirname;

var protectDir = _rootDir + '/protect/';

app.use(express.static(_rootDir));

//注册路由

app.get('/', function(req, res){

res.sendFile(_rootDir+'/src/index.html');

});

app.use(function(req, res, next) {

res.status(404).sendFile(_rootDir+'/src/404.html');

});

app.use(function(err, req, res, next) {

console.error(err.stack);

res.status(500).send('500 Error');

});

48304ba5e6f9fe08f3fa1abda7d326ab.png

上述代码实现了这几个功能,首先创建了http服务器,监听在3000端口。

然后app.use(express.static(_rootDir));这一行是使用了静态文件服务的中间件,这样我们项目下的js、css以及图片等静态文件就都可以访问到了。

接下来是注册路由,此处只匹配一个路由规则,那就是"/"(网站的根目录),当匹配到此路由后把首页文件index.html直接用res.sendFile方法给发送到浏览器端。这样浏览器用http://127.0.0.1:3001就可以访问到index.html了。网站的其他页面也可以通过配置类似的路由进行返回。express还支持配置模板引擎,默认支持ejs,你也可以自己配置其他的比如handlebars。

但是在本项目中,我们用的是angular的前端模板,所以后端就不需要模板了,没有进行配置。我们的路由机制也是完全使用的ng的前端路由,所以在express中只配置一条就够了。

在最后还有两块代码,分别是404和500错误的捕获。你可能会疑惑为什么是这样写呢?从上到下排下来就能分别捕获404和500了吗?其实这就是express的中间件机制,在此机制下,对客户端请求的处理像是一个流水线,把所有中间件串联起来,只要某个中间件把请求返回了,就结束执行,否则就从上到下一直处理此请求。

上面代码的流程就是,先按路由规则来匹配路径,如果路由匹配不到,则认为是发生404。500的错误请注意一个细节,在回调函数的参数中,第一个会传入err,就是错误对象,以此来标记是一个500错误。

理解中间件

express的核心是中间件机制,通过使用各种中间件,能够实现灵活的组装我们所需的功能。中间件是在管道中执行的,所谓管道就是像流水线一样,每到达一个加工区,相应的中间件就可以处理request和response对象,处理完后再送往下一个加工区。如果某个加工区把请求终结了,比如调用send方法返回给了客户端,那么处理就终止了。大部分情况下,都有现成的中间件供我们使用,比如用body-parser解析请求实体,用路由(路由也是一种中间件)来正确的派发请求。

比如我们在server.js中添加如下的代码:

48304ba5e6f9fe08f3fa1abda7d326ab.png

app.use(function(req, res, next){

console.log('中间件1');

next();

});

app.use(function(req, res, next){

console.log('中间件2');

});

48304ba5e6f9fe08f3fa1abda7d326ab.png

我们添加了两个中间件,请求过来之后会先被第一个捕获,然后进行处理,输出“中间件1”。后面接着执行了next()方法,就会进入下一个中间件。一个中间件执行后只有两种选择,要么用next指向下一个中间件,要么将请求返回。如果什么都不做,请求将会被挂起,也就是说浏览器端将得不到返回,一直处于pendding状态。例如上面的中间件2,将会造成请求挂起,这是应该杜绝的。

路由设计

运行起了服务器,了解了中间件编程方式,接下来我们就该为前端提供api了。比如前端post一个请求到/api/submitQuestion来提交一份数据,我们该如何接收请求并做出处理呢,这就是路由的设计了。

给app.use的第一个参数传入路径可以匹配到对应的请求,例如:

app.use('/api/submitQuestion', function(){})

这样就可以捕获到刚刚的提交试题的请求,在第二个参数中可以进行相应的处理,比如把数据插入到数据库。

但是,要注意了,express路由的正确使用姿势并不是这样的。app.use是用来匹配中间件的路径的,而不是请求的路径。因为路由也是一种中间件,所以这样的用法也是能够完成功能的,但是我们还是应该按照官方标准的写法来写。

标准的写法是什么样子呢?代码如下:

var apiRouter = express.Router();

apiRouter.post('/submitQuestion', questionController.save);

app.use('/api', apiRouter);

我们利用的是express.Router这个对象,它同样有use、post、get等方法,用来匹配请求路径。然后我们再使用app.use把apiRouter作为第二个参数传进去。

要注意的是apiRouter.post和app.use的第一个参数。app.use匹配的是请求的“根路径”,这样可以把请求分为不同的类别,比如所有的异步接口我们都叫api,那么这类请求我们就都应该挂在“/api”下。按照这样的规则,我们整个项目的路由规则如下:

48304ba5e6f9fe08f3fa1abda7d326ab.png

//注册路由

app.get('/', function(req, res){

res.sendFile(_rootDir+'/src/index.html');

});

var apiRouter = express.Router();

apiRouter.post('/getQuestion', questionController.getQuestion);

apiRouter.post('/getQuestions', questionController.getQuestions);

apiRouter.post('/submitQuestion', questionController.save);

apiRouter.post('/updateQuestion', questionController.update);

apiRouter.post('/removeQuestion', questionController.remove);

apiRouter.post('/getPapers', paperController.getPapers);

apiRouter.post('/getPaper', paperController.getPaper);

apiRouter.post('/getPaperQuestions', paperController.getPaperQuestions);

apiRouter.post('/submitPaper', paperController.save);

apiRouter.post('/updatePaper', paperController.update);

apiRouter.post('/removePaper', paperController.remove);

app.use('/api', apiRouter);

48304ba5e6f9fe08f3fa1abda7d326ab.png

在router的第二个参数中,我们传入了questionController.save这样的方法,这是什么东西呢?怎么有点MVC的味道呢?没错,我们已经能够匹配到路由了,那服务端的业务逻辑以及数据库访问等该如何组织代码呢?

用“MVC”组织代码

用MVC的结构组织代码当然是黄金法则了。express可以用模板引擎来渲染view层,路由机制来组织controller层,但是express并没有明确规定MVC结构应该怎样写,而是把自由选择交给你,自己来组织MVC结构。当然你也可以组织别的形式,比如像Java中的“n层架构”。

在本项目中,我们就以文件夹的形式来简单组织一下。因为我们使用了前端模板,所以后端的view层就不存在了,只有controller和model。看一下项目的目录:

a5f691a8ef3db20943e7a2f032390493.png

在protect下有两个文件夹controllers和models分别放C和M。我们路由中使用的questionController对象就定义在questionController.js中,来看一下用于保存试题的save方法是如何定义的:

48304ba5e6f9fe08f3fa1abda7d326ab.png

var Question = require('../models/question');

module.exports = {

//添加试题

save: function(req, res){

var data = req.body.question;

Question.save(data, function(err, data){

if(err){

res.send({success: false, error: err});

}

else{

res.send({success: true, data: data});

}

});

}

}

48304ba5e6f9fe08f3fa1abda7d326ab.png

questionController作为一个模块,使用标准的commonjs语法,我们定义了save方法,通过req.body.question,可以拿到前台传过来的数据。在这个模块中,我们require了位于model层的Question模型,没错,它就是用来操作数据库的,调用Question.save方法,这份数据就存入了数据库,然后在回调函数中,我们用res.send将json数据返回给前端。

定义好questionController后,我们就可以在server.js中把它给require进去了,然后就有了之前我们在路由中使用的

apiRouter.post('/submitQuestion', questionController.save);

整个流程就串通起来了。

models文件夹中放的就是模型了,用来管理与数据库的映射和交互,这里使用了mongoose作为数据库的操作工具,model层如何来编写,本篇就不做介绍了,在下一篇中我们再详细讲解。

最后再声明一下,本篇文章的代码是基于一个练习项目QuestionMaker,为了更好理解文章中的叙述,请查看项目的源码:https://github.com/Double-Lv/QuestionMaker

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363774.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

仔细研究Java Identity API

在深入探讨之前,让我们看一下有关Java Identity API JSR 351的一些快速事实。 这仍在进行中。 。 。 JSR是什么时候发起的? 该JSR在2011年10月通过了批准投票,随后在2011年11月成立了专家组。 谁负责此规范? Java Identity AP…

c语言按shift用户随时退出,2014年云南省“三校生”高考计算机第三次模拟试卷...

密班级: 姓名: 学号:密 封 线 内 不 得 答 题玉龙职高2012年高考第三次模拟试卷计算机基础总分:150分,考试时间:120分钟。一、单项选择题(在每小题给出的四个选项中,只有一个是符合题目要求的&a…

无状态EJB:池化和生命周期

无状态EJB池和生命周期的摘要视图(注释)。 对新手有用。 。 。 。 。 EJB池:快速概述 EJB实例存储在称为EJB池的位置–这不过是内存中的缓存 。 无状态EJB通常按需实例化,即,当客户端调用Bean上的方法时。 但是&…

代码整洁之道——有意义的命名(持续更新中)

我们给变量、参数、类、包,源代码和源代码所在目录命名,也给jar文件、war文件和ear文件命名。 We name variables, parameters, classes, packages, source code, and the directory where the source code resides, as well as jar files, war files, a…

fixed 语句(C# 参考)

fixed 语句禁止垃圾回收器重定位可移动的变量。fixed 语句只能出现在不安全的上下文中。Fixed 还可用于创建固定大小的缓冲区。 备注 fixed 语句设置指向托管变量的指针并在 statement 执行期间“钉住”该变量。如果没有 fixed 语句,则指向可移动托管变量的指针的作…

React Antd中样式的修改

如果需要对antd的样式进行修改, 进入你要修改的页面 注意:不能直接在自己的文件下面,加入一个css,修改这个class的样式,应该 加入global限定,global {} , 在{}里面写入 .classname {} 然后在设置css样式…

【Python】贪心算法入门

一.引言 本文将通过两个问题和两道例题带你入门贪心算法。 贪心算法(Greedy Algorithm)是一种在每一步选择中都采取在当前状态下最优(最好或最有利)的选择,从而希望导致全局最优解的算法。贪心算法不保证找到全局最优…

ASP.NET MVC+LINQ开发一个图书销售站点(9):编辑目录

编辑目录和新建类似,这里我们用MVC提供的辅助类 1.在Model 的BookShopDBDataContext分部类里添加: 2. 在CategoryController添加如下方法(注意:我们添加了后端验证) 3. 修改View下的EditCategory.aspx. (注意:我们用了MVC提供的辅助类生成Tex…

内外边距、浮动、布局相关

关于清除元素的内外边距: 1、行内元素只有左右边距、没有内外边距、内边距在ie6等低版本的浏览器中也会有问题。尽量不要给元素指定行内的内外边距; 2、外边距的合并 使用margin定义块元素的垂直外边距时,可能会出现外边距的合并&#xff…

让vs2008支持jQuery的智能提示!

告诉大家一个非常好的消息,就是现在我们已可以让VS2008同时支持jQuery的智能提示功能啦可以先看看下面的效果图:jquery1.png (18.76 K)2008-3-30 14:37:54jquery2.png (21.18 K)2008-3-30 14:37:54怎样?酷吧,呵呵想实现以上效果只…

为什么要使用Vuex?

为什么要使用Vuex? 1. 假如不使用 1.1 父子组件依赖同一个state 1.2 兄弟组件依赖同一个state 2. 用了Vuex之后 3. 方便记忆和理解 更多专业前端知识,请上 【猿2048】www.mk2048.com

使用注解配置Spring

使用注解配置Spring 1.为主配置文件引入新的命名空间(约束) 2.开启使用注解代理配置文件 3.在类中使用注解完成配置 将对象注册到容器 修改对象的作用范围 值类型注入 引用类型注入 注意: 初始化|销毁方法 转载于:https://www.cnblogs.com/HiJackykun/p/10428728.html

基于cookie的SSO单点登录系统

利用COOKIE实现单点登录功能 近期公司要求帮一个项目实现单点登录功能,在综合考量下决定采用cookie实现,大概的流程如下图所: 转载于:https://www.cnblogs.com/buggeerWang/p/10430770.html

js的栈与堆

JavaScript中基本数据类型和引用数据类型的区别 这是我引用别人的 觉得很好 1、基本数据类型和引用数据类型 ECMAScript包括两个不同类型的值:基本数据类型和引用数据类型。 基本数据类型指的是简单的数据段,引用数据类型指的是有多个值构成的对象。 当…

android 获取程序,Android获取桌面应用程序

转载请注明出处,谢谢:http://blog.csdn.net/harryweasley/article/details/50057029首先在看这个博客之前, 你可以先看下这个博客,http://blog.csdn.net/harryweasley/article/details/50057707里面介绍了两种方式来获取应用程序的…

等保2.0 | 几维安全发布等保检测、等保加固专版 加速企业等保合规

随着等保 2.0 时代的到来,网络安全要求更加严格,应用场景更加丰富,等级保护已成为互联网企业义不容辞的责任。作为国内移动安全领域的技术创新企业,几维安全在积极响应等保2.0时代的战略布局,推出等保2.0检测、等保加固…

js中什么是对象,对象的概念是什么?

我们一直在用对象 可是你真的理解对象吗,js中有一个说法是一切皆对象,其实这里说的应该是 一切皆可看作对象 对象就是可以拥有属性和方法的一个集合 士兵就是一个对象,它拥有身高体重的属性,保家卫国,吃饭睡觉的动作方…

又做了3个极品菜[图]

今天的是: 极品豆角炒鸡蛋 极品黄瓜炒鸡蛋 极品炒菠菜没鸡蛋 其他我做的菜请看 《我做的菜很香很好吃[有图]》 转载于:https://www.cnblogs.com/zjneter/archive/2008/04/13/1151383.html

Spring Integration Java DSL示例

现在已经为Spring Integration引入了新的基于Java的DSL ,这使得可以使用基于纯Java的配置而不是基于Spring XML的配置来定义Spring Integration消息流。 我尝试使用DSL来获得示例集成流–我称其为Rube Goldberg流 ,因为它在尝试大写作为输入传递的字符串…

automake linux,Linux下automake软件编译与发布快速入门

Linux下automake软件编译与发布快速入门2008-04-22eNet&Ciweek进入编辑界面,输入内容如下:AUTOMAKE_OPTIONSforeignbin_PROGRAMSsimserver1 #软件包名称simserver1_SOURCESsimserver1.cpp  #源文件列表,如果有多个则用空格分开LIBS -l…