使用 Ionic 2、MongoDB 和 Node 构建一个 Review App 已翻译 100%

昌伟兄 投递于 2017/01/18 11:06 (共 12 段, 翻译完成于 01-23)
阅读 2697
收藏 95
1
加载中

在整个的网页和移动开发历程中,你也许已经听说过 MEAN 技术栈, 它 (只是听起来不起眼) 所代表的是 MongoDBExpress.js,Angular, 以及 Node.js。 将所有这些技术综合到一起,就能让你创造出一个带有前台和后端的应用程序。

在本教程中我们将使用由 MEAN 技术栈驱动的 Ionic 2来创建一个简单的评论(Review)应用程序。在之前的教程《用于 HTML5 移动开发 NoSQL 介绍》中, 我们讲到了如何去使用 MongoDB, 现在我们就要来看看如何在实用的场景中对其加以运用。如果你对 MongoDB 还不熟悉的话,那么我建议你去读一读那个教程(它提供了一些简单的有关于 NoSQL 以及 MongoDB 的背景介绍),当然,在本教程中我也会讲到对其进行设置的一些步骤。

LeoXu
LeoXu
翻译于 2017/01/23 16:07
0

如下是届时应用完工我们会看到的效果:

而如下是我们在本教程中如何去利用 MEAN 技术栈的计划:

  • MongoDB 将会是我们的 NoSQL 数据库,我们将用它来存储和获取评论数据;

  • Express 可以为我们所创建的 REST API 创建路由;

  • Ionic 2 将会被用来作为应用程序的后台方案 (我觉得这样就应该叫 MEIN 技术栈才对),而没有用 Angular 2;

  • Node 将会是我们的服务器, 它会放在应用程序的前台和 MongoDB 数据库之间。

本教程藉借由下列优秀的资源的方方面面创作而来,,因此如果你想了解更多,可以点击查看:

LeoXu
LeoXu
翻译于 2017/01/23 16:16
1

1. 使用 MongoDB 创建数据库

我们要做的第一件事情就是设置好一个 MongoDB 数据库。我们将会把这个数据库放在本地 (Node 服务器也是如此),不过如果你愿意的话,也可以将数据库放到其它的地方。

如下所述的步骤只针对 Mac,我们会用到 brew。如果你还没有安装 brew 的话,只要按照这个页面上的指导去做就可以了。如果你使用的是 Windows 计算机,那么你按照这里的指导去安装 MongoDB 就可以了。

你可以使用下面的命令安装 MongoDB:

brew install mongodb

然后使用下面的命令启动它:

brew services start mongodb

现在,你可以使用下面的命令来创建一个新的 MongoDB 数据库然后连接:

mongo reviewking

现在你就可以通过终端同 reviewking 数据库交互, 而当我们将 API 弄好之后,就可以通过评论应用程序来同其进行交互了。若你想要稍后再来访问同一个数据库,只要再次运行 mongo test 即可。

LeoXu
LeoXu
翻译于 2017/01/23 16:24
0

2.生成一个新的 Ionic 2 应用程序

在创建前端之前,我们要创建好 Node 服务器,而现在先让我们弄好 Ionic 2 工程。

运行如下命令来创建一个新的 Ionic 2 应用程序:

ionic start review-king blank --v2

我们也会要创建另外一个页面 (用来添加评论)和一个 Provider (用来同 API 交互), 那么现在就来弄吧。

运行下面的生成命令:

ionic g page AddReviewPage
ionic g provider Reviews

当要在应用程序中创建新的组件时,我们需要确保它们也被添加到了 app.module.ts 文件中。

修改 src/app/app.module.ts 以反映如下内容:

import { NgModule } from '@angular/core';
import { IonicApp, IonicModule } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { AddReviewPage } from '../pages/add-review-page/add-review-page';
import { Reviews } from '../providers/reviews';
 
@NgModule({
  declarations: [
    MyApp,
    HomePage,
    AddReviewPage
  ],
  imports: [
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    AddReviewPage
  ],
  providers: [Reviews]
})
export class AppModule {}

现在我们就来设置服务器。

LeoXu
LeoXu
翻译于 2017/01/23 16:30
0

3. 使用 Node & Express 创建后台 API

我们准备爆出服务端同前端 Ionic 2 工程的分离,因此我们将会在 Ionic 工程的外面创建一个文件夹。

在你的 Ionic 工程外面创建一个叫做 server 的文件夹。

我们也需要为它设置一些依赖。你也许比较熟悉在 Ionic 工程(或者其它工程)中使用 package.json 文件来指定由 npm 安装的依赖。我们也可以在服务端文件夹中做同样的事情。

在 server 文件夹里面创建一个叫做 package.json 的文件,加入如下内容:

{
  "name": "review-king",
  "version": "0.1.0",
  "description": "A sample Node.js app using Express 4",
  "engines": {
    "node": "5.9.1"
  },
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "devDependencies": {
    "mongoose": "^4.6.2",
    "body-parser": "^1.15.2",
    "cors": "^2.8.0",
    "del": "2.2.0",
    "express": "^4.14.0",
    "http": "0.0.0",
    "method-override": "^2.3.6",
    "morgan": "^1.7.0",
    "superlogin": "^0.6.1"
  }
}

Mongoose 是一个辅助我们同 MongoDB 进行交互的封装程序,而之前我提到过 Express 会被我们从来辅助创建 API 的路由。

LeoXu
LeoXu
翻译于 2017/01/23 16:37
1

其余的依赖都是服务端的辅助程序。Body Parser 帮我们从 POST 请求中抓取信息, Method Override 提供 DELETE 和 PUT 支持, Morgan 可以输出一些有用的调试信息, 而 Cors 可以为我们处理 CORS (跨域资源共享 Cross Origin Resource Sharing)问题。

要在 package.json 中安装所有的这些依赖, 你需要运行 npm install 命令。

在终端中将目录切换到 server, 然后运行如下命令: 

npm install

现在我们将创建一个 server.js 文件, 我们会对这个文件运行 node 命令来创建服务端。我们不会深入去描述这一过程,因此如果你想要了解这个步骤的更多细节的话,建议去看看我在前面所提供资源。

注意: 这里的代码主要依赖于这个教程,在此要感谢 Chris Sevilleja。他写的教程也提供了有关这一步骤的许多细节。

在 server 文件夹里面你创建一个叫做 server.js 的文件,然后加入如下代码: 

// Set up
var express  = require('express');
var app      = express();                               // create our app w/ express
var mongoose = require('mongoose');                     // mongoose for mongodb
var morgan = require('morgan');             // log requests to the console (express4)
var bodyParser = require('body-parser');    // pull information from HTML POST (express4)
var methodOverride = require('method-override'); // simulate DELETE and PUT (express4)
var cors = require('cors');
 
// Configuration
mongoose.connect('mongodb://localhost/reviewking');
 
app.use(morgan('dev'));                                         // log every request to the console
app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
app.use(bodyParser.json());                                     // parse application/json
app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
app.use(methodOverride());
app.use(cors());
 
app.use(function(req, res, next) {
   res.header("Access-Control-Allow-Origin", "*");
   res.header('Access-Control-Allow-Methods', 'DELETE, PUT');
   res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
   next();
});
 
// Models
var Review = mongoose.model('Review', {
    title: String,
    description: String,
    rating: Number
});
 
// Routes
 
    // Get reviews
    app.get('/api/reviews', function(req, res) {
 
        console.log("fetching reviews");
 
        // use mongoose to get all reviews in the database
        Review.find(function(err, reviews) {
 
            // if there is an error retrieving, send the error. nothing after res.send(err) will execute
            if (err)
                res.send(err)
 
            res.json(reviews); // return all reviews in JSON format
        });
    });
 
    // create review and send back all reviews after creation
    app.post('/api/reviews', function(req, res) {
 
        console.log("creating review");
 
        // create a review, information comes from request from Ionic
        Review.create({
            title : req.body.title,
            description : req.body.description,
            rating: req.body.rating,
            done : false
        }, function(err, review) {
            if (err)
                res.send(err);
 
            // get and return all the reviews after you create another
            Review.find(function(err, reviews) {
                if (err)
                    res.send(err)
                res.json(reviews);
            });
        });
 
    });
 
    // delete a review
    app.delete('/api/reviews/:review_id', function(req, res) {
        Review.remove({
            _id : req.params.review_id
        }, function(err, review) {
 
        });
    });
 
 
// listen (start app with node server.js) ======================================
app.listen(8080);
console.log("App listening on port 8080");

这段代码的内容相当的多,可以简单划分为如下单独的区域:

  • 设置 Set up

  • 配置 Configuration

  • 模块 Models

  • 路由 Routes

  • 侦听 Listen

LeoXu
LeoXu
翻译于 2017/01/23 16:48
0

首先我们为服务端设置好了所有的依赖(像 Mongoose 以及 Express)。然后我们配置了一些东西,其中最重要的是包含了下面这一行:

mongoose.connect('mongodb://localhost/reviewking');

它设置了我们到数据库的连接。如果你并不想把数据库叫做 reviewking,那就要确保在这里进行了修改。我们配置了一个叫做 Review 的模型,它被用来在数据库中存储 review 对象——如你所见,这一对象由 title, description, 以及 rating 构成。

接下来我们设置路由,它是我们用来命中 API 的端点。最终我们将使用 Http 服务来命中端点。届时我们将可以:

  • 向 /api/reviews 发送一个 GET 请求来获取所有的评论

  • 向  /api/reviews 发送一个 POST 请求创建一个新的评论

  • 向 /api/reviews/{{review_id}} 发送一个 DELETE 请求来删除一条特定的评论

在上面的代码中你可以看到,我们使用了 app.get, app.post, 以及  **app.delete 对上述路由进行设置。这里面的每一个我们都指定了将要被命中的 URL,而且我们也设置了对应的处理程序(handler)。在 POST 的场景中,它将会处理将数据存储到数据库中的业务逻辑,而如果有一个 GET 请求,它就会处理获取数据并将其发送给应用的逻辑。

LeoXu
LeoXu
翻译于 2017/01/23 16:58
0

最后的 listen 这一节,会在端口 8080 启动服务端,意思就是我们可以通过访问如下链接同服务端进行交互:

http://localhost:8080

现在服务端已经就位,我们可通过运行如下命令来启动它:

node server.js

在你之后通过应用程序同服务端进行交互之后,应该会在终端中看到下面这些东西:

现在我们就需要创建前端了!

LeoXu
LeoXu
翻译于 2017/01/23 17:01
0

4. 使用 Ionic 2 创建前端

我们已经将应用程序的架构弄好了,现在只需要将前端代码放好就行了。因为这是一篇更高级一点的教程,因此我会相当快速的过一遍,只专注在重要的地方详细讲讲。

创建 Reviews Provider

我们先创建 Reviews 的 provider 开发,它是应用程序中最有趣的东西,因为它会同后台进行交互。

修改 src/providers/reviews.ts 以反映如下内容:

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import 'rxjs/add/operator/map';
 
@Injectable()
export class Reviews {
 
  data: any;
 
  constructor(public http: Http) {
    this.data = null;
  }
 
  getReviews(){
 
    if (this.data) {
      return Promise.resolve(this.data);
    }
 
    return new Promise(resolve => {
 
      this.http.get('http://localhost:8080/api/reviews')
        .map(res => res.json())
        .subscribe(data => {
          this.data = data;
          resolve(this.data);
        });
    });
 
  }
 
  createReview(review){
 
    let headers = new Headers();
    headers.append('Content-Type', 'application/json');
 
    this.http.post('http://localhost:8080/api/reviews', JSON.stringify(review), {headers: headers})
      .subscribe(res => {
        console.log(res.json());
      });
 
  }
 
  deleteReview(id){
 
    this.http.delete('http://localhost:8080/api/reviews/' + id).subscribe((res) => {
      console.log(res.json());
    });    
 
  }
 
}

这里我们创建了三个方法: getReviews, createReview, 以及 deleteReview。这里的每一个都对应到我们的 API 中的一个端点。在 getReviews 函数中,我们简单地向 /api/reviews 发送了一个 get 请求,接着会让它返回评论数据。createReview 函数会接收一个 review 对象作为参数,然后将它 posts 到 /api/reviewsendpoint(我们已经在里面对插入到数据库的操作进行了处理)。最后deleteReview 函数会接收一个指定评论的 id(它是由 MongoDB 自动创建的),然后向 API 发起请求对其进行删除。

LeoXu
LeoXu
翻译于 2017/01/23 17:24
0

创建 Add Review 页面

现在让我们对 ‘Add Review’ 页面来进行设置。这个稍后会被作为一个 Modal 被触发,这样用户就可以输入他们的标题、描述,并使用 Ionic 的评分组件输入评分。

修改 src/pages/add-review-page/add-review-page.html 以反映如下内容:

<ion-header>
 <ion-toolbar transparent>
  <ion-title>Add Review</ion-title>
  <ion-buttons end>
    <button ion-button icon-only (click)="close()"><ion-icon name="close"></ion-icon></button>
  </ion-buttons>
 </ion-toolbar>
</ion-header>
 
<ion-content>
 
  <ion-list no-lines>
 
    <ion-item>
      <ion-label floating>Title</ion-label>
      <ion-input [(ngModel)]="title" type="text"></ion-input>
    </ion-item>
 
    <ion-item>
      <ion-label floating>Review</ion-label>
      <ion-textarea [(ngModel)]="description"></ion-textarea>
    </ion-item>
 
    <ion-item>
      <ion-range min="0" max="100" pin="true" [(ngModel)]="rating">
        <ion-icon range-left name="sad"></ion-icon>
        <ion-icon range-right name="happy"></ion-icon>
      </ion-range>
    </ion-item>
 
  </ion-list>
 
  <button ion-button full color="secondary" (click)="save()">Save</button>
 
</ion-content>

修改 src/pages/add-review-page/add-review-page.ts 以反映如下内容:

import { Component } from '@angular/core';
import { ViewController } from 'ionic-angular';
 
@Component({
  selector: 'add-review-page',
  templateUrl: 'add-review-page.html'
})
export class AddReviewPage {
 
  title: any;
  description: any;
  rating: any;
 
  constructor(public viewCtrl: ViewController) {
 
  }
 
  save(): void {
 
    let review = {
      title: this.title,
      description: this.description,
      rating: this.rating
    };
 
    this.viewCtrl.dismiss(review);
 
  }
 
  close(): void {
    this.viewCtrl.dismiss();
  }
}

我们并不会在这里处理任何针对数据的保存操作,我们只是抓取用户的输入,然后通过 dimiss() 方法将其发送给 HomePage。现在我们就来对主页进行设置。

修改 src/pages/home/home.html 以反映如下内容: 

<ion-header>
 <ion-navbar transparent>
  <ion-title>
    Review King
  </ion-title>
  <ion-buttons end>
    <button ion-button icon-only (click)="addReview()"><ion-icon name="add"></ion-icon></button>
  </ion-buttons>
 </ion-navbar>
</ion-header>
 
<ion-content>
 
  <ion-list no-lines>
 
    <ion-item-sliding *ngFor="let review of reviews">
 
      <ion-item>
 
        <ion-avatar item-left>
          <img src="https://api.adorable.io/avatars/75/{{review.title}}">
        </ion-avatar>
 
        <h2>{{review.title}}</h2>
        <p>{{review.description}}</p>
 
        <ion-icon *ngIf="review.rating < 50" danger name="sad"></ion-icon>
        <ion-icon *ngIf="review.rating >= 50" secondary name="happy"></ion-icon> 
        {{review.rating}}
 
      </ion-item>
 
      <ion-item-options>
        <button ion-button color="danger" (click)="deleteReview(review)">
          <ion-icon name="trash"></ion-icon>
          Delete
        </button>
      </ion-item-options>
    </ion-item-sliding>
 
  </ion-list>
 
</ion-content>

这个模板比上面那个更有趣一点。我们利用 *ngFor 对评论数据集 reviews 进行了循环遍历(很快我们就会在类定义中对 reviews 进行定义)。数据集里面的每一个我们都会展示同这条评论相关联的数据,也会根据 title 值从 adorable.io 生成 avatar 标识。还会在评分在 50 以上的时候展示一个高兴的表情,而在其低于 50 的时候展示一个沮丧的表情。

LeoXu
LeoXu
翻译于 2017/01/23 17:33
0
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(1)

adoontheway
adoontheway
入门好文 BTW ionic是用的是angular进行数据绑定的 所以其实还是mean
返回顶部
顶部