本文同步至个人博客 MEAN.js 文档,转载请注明出处。
Overview
感谢使用 MEAN.js 框架!
本文档涵盖构建 MEAN 应用所需的基础知识。
在你开始阅读该文档之前,我们建议您阅读 MEAN.js 所使用的技术栈:
MongoDB
请至 MongoDB 官网获取 MongoDB 手册,这对了解什么是 NoSQL 和 MongoDB 大有裨益。
Express
理解 Express MVC 的最优方式依然是通过 官网,尤其是 Express 入门指南;另外,还可以从 StackOverflow(译改原链接无法使用) 上获取更多资料。
AngularJS
从 Angular 官网 开始学习是个不错的开始。此外学习 Thinkster Popular Guide 和 Egghead 视频教程 也是不错的开始。
Node.js
通读 Node.js 官网手册 及 StackOverflow Thred,可以让你尽快了解什么是 Node.js 平台。
当阅读完上述资料后,如果你感觉多这些技术有了大致了解,那么现在可以继续我们的 MEAN.js 学习了。
Enjoy & keep us updated,
The MEAN.JS Team.
一 起步
这个章节会带你学习如何使用 MEAN.js 框架,第一步就是安装所有依赖和初始化应用。
1.1 依赖
在开始前,请先确认你是否已在开发机器上安装了下面所有依赖。
- git
确认是否已在机器上安装了 Git 版本控制工具。 OSX 和 Linux 系统一般会默认安装它。可以输入下列命令确认是否已安装:
$ git --version
-- Node.js & npm
下载并安装 Node.js 和 npm 包管理器,如果你遇到任何问题,您还可以使用 Github Gist 来安装 node.js。
- MongoDB
下载并安装 MongoDB 数据库,并确保在默认端口 (27017) 启动服务。
- Bower
我们需要使用 Bower 包管理器 对前端代码进行管理,安装 Bower 需要预先安装 Node.js 和 npm,然后使用 npm 执行下面的命令进行全局安装 Bower:
$ npm install -g bower
- Gulp
我们还会使用 Glup 自动化构建工具 来管理开发组件。安装 Glup 需要预先安装 Node.js 和 npm,然后使用 npm 执行下面的命令进行全局安装 Glup:
$ npm install -g glup
Note: Your user might not have the permissions to install package globally, so use a super user or sudo.
1.2 下载 MEAN.js
我们提供有多种方式获取 MEAN.js 框架。
1.2.1 从 Github 版本库复制
使用 Git 直接从 MEAN.js 版本库复制:
$ git clone https://github.com/meanjs/mean.git <your-project-name>
1.2.2 下载 MEAN.js 压缩文件
还可以通过下载最新稳定版本的 MEAN.js 压缩包。使用 wget 命令执行下载:
$ wget https://github.com/meanjs/mean/archive/0.5.0.zip -O meanjs.zip; unzip meanjs.zip; rm meanjs.zip
不要忘记将 mean-0.5.0 重命名为你的项目名称。
1.3 安装依赖
上面所有的依赖工具安装完成后,还需简单的几步处理就可以开始开发 MEAN 应用了。
首先,需要安装 Node.js 依赖库。MEAN.js 初始项目中的 package.js 文件列出来所有项目依赖模块,如果需要了解如何安装模块可以阅读 NPM & Package.json 章节。
要安装这些项目依赖需要再次执行 npm 命令,仅仅需要运行下面的命令即可:
$ npm install
This command does a few things:
-First it will install the dependencies needed for the application to run.
- If you're running in a development environment, it will then also install development dependencies needed for testing and running your application.
- Finally, when the install process is over, npm will initiate a bower installcommand to install all the front-end modules needed for the application.
1.4 使用 Glup 启动项目
完成所有安装工作后,就可以使用 Glup 启动并运行项目,仅需执行下面的命令:
$ glup
项目会在 3000 端口执行,所以我们可以在浏览器输入 http://localhost:3000 访问项目。
That's it! your application should be running by now, to proceed with your development check the other sections in this documentation.
如果在此之前遇到什么问题,可以查阅 「排错」 章节了解详情。
二 排错
如果遇到各种疑难杂症请点击 原文
三 目录结构
MEANJS 项目的目录结构如下图所示:
<project-home> 文件夹为项目的根目录,你可以给你的项目创建指定的项目名称作为根目录名称。以下是子目录及其功能说明.
3.1 <project-home>
更目录包含以下子目录:
- 应用配置文件列表
- 应用默认配置文件列表
- 一系列用于构建和启动应用的文件
- 包含四个主要模块及相关类库的模块文件夹
3.2 config 目录
项目所有的运行时环境配置文件和辅助函数文件都放置在 config 目录中。下面详细讲解它的构成:
3.2.1 config/assets
该目录用于管理框架的资源文件。当 MEAN.js 项目运行时,用户界面需要使用的一系列静态资源皆在此管理。静态资源包括 images,CSS 样式表,JavaScript 脚本和视图(如 html 模版)。
另外,依据不同的开发环境 (NODE_ENV) 将会动态加载不同环境的资源管理文件(如: dev, test, prod)。该目录中的配置是用于告知项目在运行中需要使用的所有静态资源以及如何查找相关文件路径。
3.2.2 config/env
该目录用于管理 MEAN.js 项目运行时,提供针对不同开发环境(如: local, dev, test, prod)的配置设置。
3.2.3 config/lib
lib 目录是各种辅助函数文件的管理目录,用于 MEAN.js 使用的各个模块就放置于此。
目录中包含提供引导应用启动的组件,创建 express 实例的组件,创建日志服务的组件,创建 MongoDB 连接实例组件,多文件上传组件,创建测试用户数据组件及创建 socket 连接服务的组件等。
3.3 modules 目录
modules 目录是 MEAN.js 应用的 AngularJS 前端业务逻辑模块的管理目录。当你创建各种前端业务逻辑时,每个功能特性建议以独立命名的文件名作为一个独立的模块进行管理。正如 AngularJS 开发指南 描述的那样, 「你可以将一个功能模块视作应用中对应部分的容器」。
MEAN.js 中提供了部分开箱即用的常用模块,你需要做的是创建自己项目中需要涉及的功能模块即可。
modules 目录下的子目录,以下面的目录结构进行组织管理:
3.3.1 modules/*/client
前端代码,相关资源文件和特定的模块将在此目录下进行管理。
3.3.2 modules/*/server
服务端代码,相关资源文件和特定的模块将在此目录下进行管理。
3.3.3 modules/*/tests
用于数据校验的组件及相关文件在此目录进行管理。
3.4 public 目录
项目中所有前端使用的静态资源都放置在这个目录中。静态文件包括构建应用的资源文件及使用的外部第三方类库。
public 目录中包括如下两个子目录:
3.4.1 public/lib
public/lib 包含应用所使用的外部类库及由 bower 引入的资源文件。
3.4.2 public/dist
public/dist 用于存放构建后的资源文件。例如,生产环境中所使用压缩后的脚本文件。
3.5 scripts 目录
scripts 目录存放开发,管理和操作项目的脚本文件。
4 Express
每个优秀的 Web 应用最终都是一个 Web 框架。MEAN.js 使用的是 Express MVC 框架。Express 是这样介绍的 「Express 是一个简洁而灵活的 node.js Web应用框架, 提供一系列强大特性帮助你创建各种Web应用 ...」
Express 的启动配置在 config/lib/express.js 文件里。本节我们来聊聊在 MEAN.js 中要如何配置和启动 Express。
4.1 可配置的属性
4.1.1 app.locals
在 MEAN.js 里可以使用 app.locals 设置自定义的变量。变量一经设置即可在整个项目生命周期内使用。如果需要在前端代码使用某个全局变量,这个特性会非常有用,比如 users/sessions 链接到服务器。
4.1.2 res.locals
此外 Express 应用还具有存储响应数据到本地变量的能力,比如 res.locals 就可以存储请求数据。MEAN.js 就是用了这个特性。Express 中的 res 对象会存储某个 HTTP 请求的响应的数据。从 API 文档中我们可以看出如果需要获取请求数据 res.locals 功能会非常有用。
4.2 路由
使用 Express 框架的优势之一就是提供开箱即用的路由功能。在 MEAN.js 中,路由主要处理来自前端的 URL 跳转和处理 HTTP 请求。
一个请求的 URL 通常包括几个部分:资源定位符,查询字符串以及片段信息等。
此外,一个 HTTP 请求还包含请求方法。 This is the desired action to be performed on the resource specified by the URL。常用的请求方法包括:GET, POST, PUT 和 DELETE。
请求的 URL 地址和请求方式共同组成一个路由。在 MEAN.js 中会在路由配置里定义处理不同请求的方法。为了实现路由功能,我么直接使用 Express 的路由功能。在 Express 官网的 路由使用 中有讲解如何定义一个路由:
app.METHOD(PATH, HANDLER)
- app 是一个 Express 实例;
- METHOD 为 HTTP 请求方法;
- PATH 对应 URL 中的路径;
- HANDLER 是当匹配到的路由时,用于处理请求的方法。
4.3 中间件
Express 设计哲学中一个重要组成部分就是为 Web 应用提供中间件框架。Express 作者这样 描述过中间件 「中间件可以访问请求和响应对象中的所有数据,并通过 next() 函数将请求传送回请求-响应声明周期中的下一个处理」。
需要注意的是在 MEAN.js 中自定义中间件的顺序非常重要。当项目启动时,中间件的定义顺序决定了它们的执行顺序。
除了自定义中间件外,MEAN.js 还是用了诸多第三方的中间件,它们是:
- compression
- serve-favicon
- method-morgan
- body-parser
- override
- cookie-parser
- connect-flash
- express-session
- lusca
- helmet
五 测试
我们使用 Mocha 组件对服务端代码进行测试。它是一款异步可维护的采用 BDD 语法的测试框架
5.1 断言
Mocha needs an external assertion library to predicate the result of each test, in this case Should.js is being used. Should is an expressive library aiming to simplify tests and be readable. It extends the Object.prototype with a single non-enumerable getter that allows you to express how that object should behave.
5.2 Test Files
Each entity have its own test file located inside their respective module server tests folder. Ex.: modules/core/tests/server
5.3 Writing Tests
There are a few common steps we use to test an entity:
- In the beforeEach or before functions take care of prerequisites and create the objects you are about to use in your tests.
- For each test start with a describe function to indicate which method is being tested.
- Next, add your scenario tests using the it function.
- In the it function run the tests functionality and use should to assert what the end result should be.
- Finally use after or afterEach functions to finalize your tests and clear the test database.
六 认证
Passport is an authentication middleware, which allows you to implement many authentication methods in your Express application.
Passport utilizes a modular approach that uses authentication strategies modules, offering a simple, configurable authentication solutions.
This boilerplate comes pre-bundled with 7 authentication mechanisms implemented in the config/passport.js file:
Local
The Local Strategy is used to authenticate users via username and password.
The Facebook Strategy is used to authenticate users via their Facebook account.
Github
The Github Strategy is used to authenticate users via their Github account.
The Google Strategy is used to authenticate users via their Google account.
The Linkedin Strategy is used to authenticate users via their Linkedin account.
PayPal
The PayPal Strategy is used to authenticate users via their PayPal account.
The Twitter Strategy is used to authenticate users via their Twitter account.
七 创建 AngularJS 导航
MEAN.js 提供了一个创建和管理 AngularJS 导航功能组件。这个组件提供很多使用方法:
Menus.getMenu(menuid)
返回导航 ID 为 menuid 的菜单对象。
var menu = Menus.getMenu('myMenu');
Menus.addMenu(menuId, [options])
创建标识为 menuId 的导航:
- menuId 必选 - 识别当前导航
-
options 可选,默认值为 {} - 值为导航对象信息,包括:
- items 默认 [] - 一个菜单项的数组,用来初始化菜单。
- roles 默认 ['user', 'admin'] - 能够以允许查看此菜单的角色的数组。
Menus.addMenu('myMenu', {roles:'*'});
Menus.removeMenu(menuId)
删除一个导航配置.
Menus.removeMenu('myMenu');
Menus.addMenuItem(menuId, [options])
创建一个新的导航对象。方法一样包含两个参数:
- menuId (Required) - 识别当前导航
-
options (Optional; Default: {}) - 导航选项具体初始化选项。可能的选项包括:
- title (Optional; Default: '') - 导航名称.
- state (Optional; Default: '') - The UIRoute value, which is used to define the URL scheme where this menu item is marked as active.
- type (Optional; Default: 'item') - 值为 'item' 或 'dropdown'.
- class (Optional; Default: undefined) - CSS class(es) to apply to the menu list item (li) that is created.
- roles (Optional; Default: menu.roles) - An array indicating the roles that are allowed to view this menu item.
- position (Optional; Default: 0) - Specify the order of appearance.
Menus.addMenuItem('topbar', {title: 'Menu Item', state: 'menuitemstate'});
Menus.removeMenuItem(menuId, menuItemState)
删除给定的导航配置。方法接收两个参数:
- menuId (Required) - 识别当前导航
- menuItemState (Required) - Indicates the menu item state that should be removed.
Menus.removeMenuItem('topbar', 'menuitemstate');
Menus.addSubMenuItem(menuId, parentItemState, [options])
向给定标识符导航元素中添加子导航对象。
- menuId (Required) - 识别当前导航
- parentItemState (Required) - Indicates the parent menu item state.
-
options (Optional; Default: {}) - Indicates the options object to initialize the sub menu item with. Possible options include:
- title (Optional; Default: '') - A String title for the menu item.
- state (Optional; Default: '') - The UIRoute value, which is used to define the URL scheme where this menu item is marked as active.
- roles (Optional; Default: parent.roles) - An array indicating the roles that are allowed to view this menu item.
- position (Optional; Default: 0) - Specify the order of appearance.
Menus.addSubMenuItem('topbar', 'dropdown1state', {title: 'Sub Menu Item', state: 'submenuitemstate'});
Menus.removeSubMenuItem(menuId, submenuItemState)
从已有导航中删除给定标识的导航配置。接收两个参数:
- menuId (Required) - 识别当前导航
- submenuItemState (Required) - Indicates the sub menu item state that should be removed.
Menus.removeSubMenuItem('topbar', 'submenuitemstate');
导航信息配置通常在应用模块中进行定义配置。一个简单的导航配置示例如下:
angular.module('example').run(['Menus',
function(Menus) {
Menus.addMenuItem('topbar', {title: 'Example', state: 'example'});
Menus.addMenuItem('topbar', {title: 'Example Dropdown', state: 'exampledropdown', type: 'dropdown'});
Menus.addSubMenuItem('topbar', 'exampledropdown', {title: 'Example Sub Item', state: 'examplesubitem'});
}
]);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。