成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Ember.js如何與后端服務(wù)交互?adapter、store、ember data關(guān)系揭秘

huhud / 1841人閱讀

摘要:目前打算本項目使用種數(shù)據(jù)交互方式一種是,一種是。要理解后端服務(wù)的關(guān)系我們從他們各自的概念入手。創(chuàng)建服務(wù)端如何在項目中創(chuàng)建服務(wù)端程序呢提供了創(chuàng)建的命令。

文章來源:Ember Teach

本項目講解如何使用adapter、EmberData以及怎么連接到本地數(shù)據(jù)庫。

項目簡介 主要內(nèi)容

適配器使用

如何持久化數(shù)據(jù)到本地數(shù)據(jù)庫

簡單的后端服務(wù)

最近經(jīng)常有初學(xué)的開發(fā)者請教有關(guān)Adapter或者Ember Data的問題。官方教程中講到這兩個內(nèi)容的是Model這一章節(jié)。本文中介紹到的內(nèi)容大部分是由這一章來的,如果有不妥請看原文或者給我留言。

注意:本文是基于v2.6.0講解。

軟件需求

MySQL

nodejs,express

body-parser

mysql-node

Ember項目常規(guī)運行軟件

Git

Node.js (with NPM)

Bower

Ember CLI

PhantomJS

用到的軟件、插件都是有關(guān)后端服務(wù)的,mysql-node用于連接、操作MySQL數(shù)據(jù)庫。后端服務(wù)是用node寫的所以也用node項目的插件連接、操作數(shù)據(jù)庫了,有關(guān)如何使用node操作MySQL的信息請看這篇文章[nodejs連接MySQL,做簡單的CRUD
](http://blog.ddlisting.com/201...。如果你的后端是其他語言寫只需要保證你后端返回的數(shù)據(jù)格式或者我的后端返回的數(shù)據(jù)格式一致就行了。目前打算本項目使用2種數(shù)據(jù)交互方式:一種是jsonapi,一種是restapi。

jsonapi

rest api

項目搭建

項目的搭建就不再費口舌了,Ember Teach已經(jīng)有很多博文介紹過了。

運行項目

如果你想運行本項目請按照下面的步驟操作:

安裝

下載代碼到本地 git clone https://github.com/ubuntuvim/emberData-adapter-database

進(jìn)入項目目錄 cd emberData-adapter-database

安裝npm依賴包 npm install

安裝bower依賴包 bower install

運行

在項目目錄下執(zhí)行命令 ember server 運行項目。

待項目啟動完畢,在瀏覽器打開http://localhost:4200。

發(fā)布到服務(wù)器

執(zhí)行命令編譯、打包項目 ember build --environment production

命令執(zhí)行完畢會在dist目錄下得到項目打包后的文件。

把打包后的dist目錄下的所有文件復(fù)制到服務(wù)器應(yīng)用目錄下運行即可(比如tomcat服務(wù)器則放到webapps目錄下)。

項目結(jié)構(gòu)

簡單起見我就做一個頁面就行了,我希望做出的效果是使用自定義的適配器獲取到本地MySQL數(shù)據(jù)庫的數(shù)據(jù)并分頁展示。

創(chuàng)建文件

使用ember-cli命令創(chuàng)建文件。

ember g route users
ember g model user username:string email:string
ember g adapter application

目前暫時只用到這幾個文件,后續(xù)可能還有其他的用到在創(chuàng)建。
ember g model user username:string email:string的作用是創(chuàng)建模型的同時創(chuàng)建2個屬性,并且屬性都指定為string類型。

說了一大堆廢話下面開始正題。要理解adapter、ember data、后端服務(wù)的關(guān)系我們從他們各自的概念入手。首先我們先理清楚他們之間的關(guān)系然后在動手實踐。理論總是繁瑣的但是也是最重要的。

========================= 華麗的分割線 =========================

體系結(jié)構(gòu)概述

注:圖片來自官方文檔

注意觀察上圖的結(jié)構(gòu)。

APP(一般是從route、controller或者component發(fā)請求)請求數(shù)據(jù)。

請求并沒有直接發(fā)送到后端服務(wù)而是先在store(ember data其實就是一個store)緩存中查找,ember之所以能實現(xiàn)動態(tài)更新模板數(shù)據(jù)也是因為有了store

如果請求的數(shù)據(jù)存在在store中,則直接返回到routecontroller或者component;如果在store中沒有發(fā)現(xiàn)請求的數(shù)據(jù),所以請求的數(shù)據(jù)是首次,數(shù)據(jù)還未緩存到store中,則請求繼續(xù)往下到了apdater層。

adapter中,adapter會根據(jù)請求的調(diào)用方法構(gòu)建出對應(yīng)的URL。比如在route、controller或者component中執(zhí)行方法findRecord("user", 1),此方法作用是查詢id為1的user數(shù)據(jù)。適配器構(gòu)建出來的URL為: http://domain/user/1,然后發(fā)請求到后端。

適配器會對比后端接受的數(shù)據(jù)格式與ember data發(fā)送的數(shù)據(jù)格式,如果不一致需要在適配器的``方法中格式化發(fā)送的數(shù)據(jù)格式。請求經(jīng)過適配器構(gòu)建得到URL后發(fā)送到后端服務(wù),后端服務(wù)根據(jù)URL請求查詢數(shù)據(jù)庫然后格式化數(shù)據(jù)格式返回到適配器。

適配器根據(jù)得到的數(shù)據(jù)和ember data所接受的數(shù)據(jù)格式匹配,如果格式不一致需要在適配器的``方法中格式化后端返回的數(shù)據(jù)。

經(jīng)過適配器之后數(shù)據(jù)轉(zhuǎn)到ember data(store)中,首先緩存到store中,然后返回到調(diào)用處(route、controllercomponent

數(shù)據(jù)請求完畢

注意:findRecord("user", 1)方法執(zhí)行過程,請求的findRecord("user", 1)方法會在Ember Data內(nèi)部解析為find方法,find方法會首先在store緩存中查數(shù)據(jù),如果沒有則會流轉(zhuǎn)到adapter中組裝URL并格式化請求數(shù)據(jù),然后發(fā)送到后端服務(wù)。

從圖中看到從適配器返回的數(shù)據(jù)是promise所以調(diào)用findRecord方法獲取數(shù)據(jù)的時候需要then()。同時可見這是個移步請求,只有promises執(zhí)行成功才能得到數(shù)據(jù)。也就是說如果考慮周全的話還需要在findRecord的時候處理promises執(zhí)行失敗的情況。

另外如果你想跳過store不需要這層緩存也是可以的。會可以這樣做:store.findRecord(type, id, { reload: true })使用reload屬性設(shè)置為true讓每次請求都跳過store直接發(fā)送請求到后端,對于實時性要求高的APP則需要這樣處理。

介紹完架構(gòu)之后將追個介紹其中的每個主要的功能特性。
需要說明的是:Models, records, adapters以及store都是Ember Data最核心的東西,他們是包含的關(guān)系,只要使用了Ember Data才能使用modelstore功能。有些初學(xué)者老是問這幾個東西的關(guān)聯(lián),希望看到這里的同學(xué)不要在提這樣的問題了??!=^=

Ember Data是Ember.js非常重要的一塊,提供了幾乎所有操作數(shù)據(jù)的API,詳細(xì)請看EMBER-DATA MODULE。當(dāng)然,如果你不想使用Ember Data也是可以的,那么你的程序直接使用Ajax與后臺交互也是可以的,或者說你使用其他類似Ember Data的插件也行。Ember Data在MVC模式中屬于M層的東西,沒有這層也并不影響到整個APP!

補充一下下

如果你不使用Ember Data,在這里提供一個簡單的方案供參考。
如果你想獲取后端數(shù)據(jù)并顯示數(shù)據(jù)到組件上(模板調(diào)用組件),你可以像下面的代碼這樣處理:

// app/components/list-of-drafts.js
export default Ember.Component.extend({
  willRender() {
    $.getJSON("/drafts").then(data => {
      this.set("drafts", data);
    });
  }
});

這里不同過Ember Data,自然也就沒有調(diào)用Ember Data提供的方法(比如,findAll、findRecord),而是直接發(fā)Ajax請求,得到數(shù)據(jù)到設(shè)置到對象drafts中,然后在模板上顯示數(shù)據(jù)。


    {{#each drafts key="id" as |draft|}}
  • {{draft.title}}
  • {{/each}}

這樣處理是沒問題的,但是當(dāng)數(shù)據(jù)改變的可能不能立即在模板上更新,因為這里無法使用store自然也就無法像計算屬性那樣當(dāng)數(shù)據(jù)有變就立即更新模板。另一個問題是當(dāng)你的請求很多的時候你需要寫很多這樣的方法,代碼復(fù)用性也比較差。

Models

In Ember Data, each model is represented by a subclass of Model that defines the attributes, relationships, and behavior of the data that you present to the user.

從使用上講,model其實就是與后端數(shù)據(jù)表對應(yīng)的實體類(借用java中的說法),通常我們的model類的定義是與后端數(shù)據(jù)表對應(yīng)的,最常見的就是model屬性的定義,建議屬性名和數(shù)據(jù)表字段名一致并且使用駝峰式命名規(guī)范。

model之間還可以定義單向或者雙向的一對一、一對多和多對多關(guān)系,這個與數(shù)據(jù)表之間的關(guān)系定義是相似的。比如下面的model:

簡單model定義
//app/models/person.js
import Model from "ember-data/model";
import attr from "ember-data/attr";

export default Model.extend({
  firstName: attr("string"),
  birthday:  attr("date")
});

model類可以直接使用ember-cli命令創(chuàng)建:

ember g model person

上面代碼創(chuàng)建了一個簡單的model,并且包含了3個屬性,一個是string類型一個是date類型,那么第三個屬性是什么了??是id,Ember會默認(rèn)為每個model增加一個屬性id,開發(fā)者不需要手動去定義這個屬性,并且如果你是手動在model類中定義這個屬性會報錯的??!那么對應(yīng)后端的服務(wù)也應(yīng)該有一個person表,并且表里也有三個字段,它們是firstName、birthday以及id

更多有關(guān)model之間關(guān)系的介紹不行本文的重點,請看第六章 模型的詳細(xì)介紹。

有了model之后程序要使用model類必須要實例化,實例化的model稱為records。

Records

A record is an instance of a model that contains data loaded from a server. Your application can also create new records and save them back to the server. A record is uniquely identified by its model type and ID.

簡單講record就是一個包含數(shù)據(jù)的model實例。說白了就是一個JSON對象(雖然這樣的說法不是很正確,但是可以反映出這是一個什么樣的對象結(jié)構(gòu))。

比如下面的代碼:

this.get("store").findRecord("person", 1); // => { id: 1, name: "steve-buscemi" }

執(zhí)行完方法findRecord后返回的就是一個model實例也就是一個record。這個record包含了數(shù)據(jù){ id: 1, name: "steve-buscemi" }。

Adapter

An adapter is an object that translates requests from Ember (such as "find the user with an ID of 123") into requests to a server.

適配器,顧名思義!作用就是做適配工作的,保存轉(zhuǎn)換數(shù)據(jù)格式、定義交互的URL前綴、構(gòu)建URL等等。在前面體系結(jié)構(gòu)已經(jīng)詳細(xì)介紹過,不在贅述。

Caching

緩存在Ember中是非常重要的,但是有一點需要注意的是不要把太多數(shù)據(jù)緩存到store中,數(shù)據(jù)量太大瀏覽器受不了!緩存的作用是非常明顯的,前面也介紹了他的作用,特別是在請求數(shù)據(jù)的時候,如果能在緩存中獲取的則立即返回到調(diào)用處,只有在緩存中查不到的數(shù)據(jù)才發(fā)請求到服務(wù)端,通常是第一次獲取的數(shù)據(jù)的時候緩存沒有則需要發(fā)請求到服務(wù)端。也正是有了緩存Ember才能快速把數(shù)據(jù)的變化響應(yīng)到模板上。

到此主要核心的概念介紹完畢了,不算多,但是認(rèn)真看下來還是很有益的??!

下面接著是如何實踐了……

創(chuàng)建數(shù)據(jù)庫

本例子使用的是MySQL數(shù)據(jù)庫,有關(guān)數(shù)據(jù)庫的安裝以及使用不在本文講解范圍,請自行學(xué)習(xí)!

建表

怎么建表我也不說了,下面直接貼建表的SQL。

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) DEFAULT NULL,
  `email` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

創(chuàng)建一個名為user的數(shù)據(jù)表。

創(chuàng)建服務(wù)端

如何在ember項目中創(chuàng)建服務(wù)端程序呢?ember提供了創(chuàng)建的命令。

ember g server

創(chuàng)建完畢之后再按照開始介紹的依賴插件。

npm install mysql-node
npm install body-parser
npm install supervisor

創(chuàng)建的是一個node服務(wù)端程序,運行的端口也是4200,不需要另外手動去啟動node服務(wù),只要ember項目運行了會自動運行起來的。

到此所有的原料都準(zhǔn)備好了,下面驗證一下項目是否還能正常運行。啟動項目,然后在瀏覽器打開http://localhost:4200。還能看到Welcome to Ember說明是成功的!

有了原料開始做菜吧!?。?/p> 編寫user模塊 更改URL方式

為了不使服務(wù)端和Ember請求URL沖突修改了URL的默認(rèn)方式,修改config/environment.js的第8行代碼為如下:

locationType: "hash",

auto改為hash。訪問Ember項目的URL則需要注意:http://localhost:4200/users改為http://localhost:4200/#/users。增加一個#號。

獲取數(shù)據(jù)、顯示數(shù)據(jù)

首先簡單列出數(shù)據(jù)庫數(shù)據(jù)。


用戶列表

{{#each model as |user|}} {{/each}}
# 用戶名 郵箱
{{user.id}} {{user.username}} {{user.email}}
// app/routes/users.js
import Ember from "ember";

export default Ember.Route.extend({
  model() {
    return this.store.findAll("user");
  }
});

目前項目還沒連接到任何數(shù)據(jù)庫,也沒有使用自定義的適配器,如果直接執(zhí)行http://localhost:4200/#/users可以在控制臺看到是會報錯的。那么下一步該如何處理呢??

加入適配器 使用RESTAdapter

先從適配器下手!在前面已經(jīng)創(chuàng)建好了適配器,如果是2.0之后的項目默認(rèn)會創(chuàng)建JSONAPIAdapter這個適配器所接收、發(fā)送的數(shù)據(jù)格式都必須符合jsonapi規(guī)范,否則會報錯,無法正常完成數(shù)據(jù)的交互。不過為了簡便我們先不使用這個適配器,改用另一個簡單的適配器RESTAdapter,這個適配器不是需要遵循jsonapi規(guī)范,只要自己約定好前后端的數(shù)據(jù)格式即可。

// app/adapters/application.js

// import JSONAPIAdapter from "ember-data/adapters/json-api";
import DS from "ember-data";

export default DS.RESTAdapter.extend({

});

手動修改好之后的適配器還不能起作用,這個適配器并沒有連接到任何的后端服務(wù),如果你想連接到你的服務(wù)上需要使用屬性host指定。

// app/adapters/application.js

// import JSONAPIAdapter from "ember-data/adapters/json-api";
import DS from "ember-data";

export default DS.RESTAdapter.extend({
  host: "http://localhost:4200"
});

等待項目重啟完畢,仍然是訪問http://localhost:4200/#/user,在控制臺仍然看到前面的錯誤,截圖如下:

為何還是錯誤呢?如果能看到錯誤說明你的程序是正確,到目前為止還沒提供任何的后端服務(wù),雖然前面使用ember g server創(chuàng)建了node后端服務(wù),但是并沒有針對每個請求做處理。當(dāng)你訪問路由user在進(jìn)入回到model時候會發(fā)送請求獲取所有模型user數(shù)據(jù),請求首選轉(zhuǎn)到Ember Data(store),但是在store中并沒有,然后請求繼續(xù)轉(zhuǎn)到適配器RESTAdapter,適配器會構(gòu)建URL得到GET請求http://localhost:4200/users,至于是如何構(gòu)建URL的請看build url method。這個請求可以在報錯的信息中看到。但是為何會報錯呢?很正常,因為我的后端服務(wù)并沒響應(yīng)這個請求。下面針對這個請求做處理。

修改server/index.js。

/*jshint node:true*/

// To use it create some files under `mocks/`
// e.g. `server/mocks/ember-hamsters.js`
//
// module.exports = function(app) {
//   app.get("/ember-hamsters", function(req, res) {
//     res.send("hello");
//   });
// };

module.exports = function(app) {
  var globSync   = require("glob").sync;
  var mocks      = globSync("./mocks/**/*.js", { cwd: __dirname }).map(require);
  var proxies    = globSync("./proxies/**/*.js", { cwd: __dirname }).map(require);

  // Log proxy requests
  var morgan  = require("morgan");
  app.use(morgan("dev"));

  // 對象轉(zhuǎn)json
  //  const serialise = require("object-tojson")
  const bodyParser = require("body-parser");

  mocks.forEach(function(route) { route(app); });
  proxies.forEach(function(route) { route(app); });

  app.use(bodyParser.urlencoded({ extended: true }));


  // 處理請求 http://localhost:4200/user
  app.get("/users", function(req, res) {
    // 返回三個對象
    res.status(200).send({
        users: [
          {
            id: 1,
            username: "ubuntuvim",
            email: "123@qq.com"
          },
          {
            id: 2,
            username: "ddlisting.com",
            email: "3333@qq.com"
          },
          {
            id: 3,
            username: "www.ddlising.com",
            email: "1527254027@qq.com"
          }
        ]
    });
  });

};

在服務(wù)端增加了一個node請求處理,攔截/users這個請求。對于express不是本文的重點,請自行學(xué)習(xí),網(wǎng)址expressjs.com。如果你使用的是其他語言的服務(wù)端程序,那么你只需要返回的json格式為:{"modelName":[{"id":1,"屬性名":"屬性值","屬性名2":"屬性值2"},{"id":2,"屬性名3":"屬性值3","屬性名4":"屬性4"}]},只需要格式正確適配器就能正確解析返回的數(shù)據(jù)。

另外再多介紹一個屬性namespace,這個屬性是用于定義URL前綴的,比如下面的適配器定義:

// app/adapters/application.js

// import JSONAPIAdapter from "ember-data/adapters/json-api";
import DS from "ember-data";

export default DS.RESTAdapter.extend({
  namespace: "api/v1",
  host: "http://localhost:4200"
});

如果是這樣定義那么后端處理的URL也需要做相應(yīng)的處理,需要在攔截的請求上加前綴,比如下面的代碼。

// 處理請求 http://localhost:4200/api/v1/user
  app.get("/api/v1/users", function(req, res) {
    // 返回三個對象
    res.status(200).send({
        users: [
          {
            id: 1,
            username: "ubuntuvim",
            email: "123@qq.com"
          },
          {
            id: 2,
            username: "ddlisting.com",
            email: "3333@qq.com"
          },
          {
            id: 3,
            username: "www.ddlising.com",
            email: "1527254027@qq.com"
          }
        ]
    });
  });

之前面唯一不同的就是請求的URL不一樣了,原來是http://localhost:4200/users改為http://localhost:4200/api/v1/users。那么這樣做的好處是什么呢?當(dāng)你的后端的API更新的時候這個設(shè)置是非常有用的,只需要設(shè)置命名前綴就能適應(yīng)不用版本的API。

項目重啟之后,再次進(jìn)入到路由users可以看到返回的3條數(shù)據(jù)。如下截圖:

到此,我想你應(yīng)該知道個大概了吧?。「嘤嘘P(guān)適配器的介紹請看下面的2篇博文:

adapter與serializer使用示例一

adapter與serializer使用示例二

使用JSONAPIAdapter

使用JSONAPIAdapter適配器和使用RESTAdapter適配器有何不同呢?我覺得最重要的一點是:數(shù)據(jù)規(guī)范。JSONAPIAdapter適配器要求交互的數(shù)據(jù)格式必須遵循jsonapi規(guī)范,否則是不能完成數(shù)據(jù)交互的。要求高了相應(yīng)的你的處理代碼也相應(yīng)的要復(fù)雜。下面我們改用JSONAPIAdapter處理。

// app/adapters/application.js

import JSONAPIAdapter from "ember-data/adapters/json-api";
import DS from "ember-data";

// export default DS.RESTAdapter.extend({
export default JSONAPIAdapter.extend({
  namespace: "api/v1",
  host: "http://localhost:4200"
});

修改適配器為JSONAPIAdapter。如果你不修改后端的服務(wù)那么控制臺可以看到報錯信息。

從截圖當(dāng)中可以清楚地看到報錯出來的錯誤,must return a valid JSON API document必須是一個有效jsonapi文檔。要修復(fù)好這個錯誤也很簡單,只需要滾吧后端服務(wù)返回的數(shù)據(jù)格式改成jsonapi的就行了。請看下面的代碼:

// 處理請求 http://localhost:4200/user
  app.get("/api/v1/users", function(req, res) {
    // 返回三個對象
    // res.status(200).send({
    //     users: [
    //       {
    //         id: 1,
    //         username: "ubuntuvim",
    //         email: "123@qq.com"
    //       },
    //       {
    //         id: 2,
    //         username: "ddlisting.com",
    //         email: "3333@qq.com"
    //       },
    //       {
    //         id: 3,
    //         username: "www.ddlising.com",
    //         email: "1527254027@qq.com"
    //       }
    //     ]
    // });
  
    // 構(gòu)建jsonapi對象
    var input = {
        data: [
            {
                id: "1",
                type: "user",  //對應(yīng)前端程序中模型的名字
                attributes: {   // 模型中的屬性鍵值對
                    username: "ubuntuvim", property: true,
                    email: "123@qq.com", property: true
                }
            },
            {
                id: "2",
                type: "user",  //對應(yīng)前端程序中模型的名字
                attributes: {   // 模型中的屬性鍵值對
                    username: "ddlisting.com", property: true,
                    email: "3333@qq.com", property: true
                }
            },
            {
                id: "3",
                type: "user",  //對應(yīng)前端程序中模型的名字
                attributes: {   // 模型中的屬性鍵值對
                    username: "www.ddlising.com", property: true,
                    email: "1527254027@qq.com", property: true
                }
            }
        ]
    };

    res.status(200).send(JSON.stringify(input));
  });

注:為了構(gòu)建jsonapi對象更加簡便另外在安裝一個插件: npm install jsonapi-parse。安裝完畢后手動關(guān)閉再重啟項目。然后再次進(jìn)入路由users可以看到與前面的結(jié)果一樣,正確了顯示后端返回的數(shù)據(jù)。

到此,我相信讀者應(yīng)該能明白這兩個適配器之間的差別了!需要注意的是Ember.js2.0版本之后JSONAPIAdapter作為默認(rèn)的適配器,也就是說平常如果你沒有自定義任何適配器那么Ember Data會默認(rèn)使用的是JSONAPIAdapter適配器。所以如果你沒有使用其他的適配器那么你的后端返回的數(shù)據(jù)格式必須是遵循jsonapi規(guī)范的。另外在路由users.js中使用到Ember Data提供的方法findAll("modelName"),我想從中你也應(yīng)該明白了Ember Data是何等重要了吧

看到這里不知道讀者是否已經(jīng)明白適配器和后端服務(wù)的關(guān)聯(lián)關(guān)系?如果有疑問請給我留言。
文中所說的后端就是我的node程序(放在server目錄下),前端就是我的Ember.js項目。

下面就是再結(jié)合數(shù)據(jù)庫。

加入數(shù)據(jù)庫

其實到這步加不加數(shù)據(jù)庫已經(jīng)不那么重要了!重要把服務(wù)端返回的數(shù)據(jù)改成從數(shù)據(jù)庫讀取就完了。我就簡單講解了。

連接MySQL

連接MySQL的工作交給前面已經(jīng)安裝好的node-mysql,如果還沒安裝請執(zhí)行命令npm install mysqljs/mysql進(jìn)行安裝。繼續(xù)修改后端服務(wù)代碼server/index.js。

module.exports = function(app) {
  // 與之前的內(nèi)容不變 
  // 
  // 引入MySQL模塊
  var mysql = require("mysql");
  // 獲取連接對象
  var conn = mysql.createConnection({
      host: "localhost",
      user: "root",
      password: "",
      // 開啟debug,可以在啟動ember項目的終端看到更多詳細(xì)的信息
      database: "test"
  });

  // 處理請求 http://localhost:4200/user
  app.get("/api/v1/users", function(req, res) {

    var jsonArr = new Array();

    // 打開數(shù)據(jù)庫連接
    conn.connect();
    //查詢數(shù)據(jù)
    conn.query("select * from user", function(err, rows, fields) {
        if (err) throw err;

        //遍歷返回的數(shù)據(jù)并設(shè)置到返回的json對象中
        for (var i = 0; i < rows.length; i++) {
            
            jsonArr.push({
                id: rows[i].id,
                username: rows[i].username,
                email: rows[i].email
            });
        }

        // 返回前端
        res.status(200).send({
            users: jsonArr
        });

    });
    // 關(guān)閉數(shù)據(jù)庫連接
    conn.end();
  });

};

相比之前的代碼只是引入了mysql,增加連接對象聲明,然后在請求處理方法里查詢數(shù)據(jù),默認(rèn)在數(shù)據(jù)庫初始化了3條數(shù)據(jù),如下截圖,另外 為了簡單起見我仍然使用的是RESTAdapter適配器,這樣處理也相對簡單。 獲取連接對象的代碼應(yīng)該不用過多解釋了,就是填寫你本地連接數(shù)據(jù)庫的對應(yīng)配置信息就行了。

記得修改適配器為RESTAdapter。

重啟項目。進(jìn)入路由users可以看到數(shù)據(jù)庫的數(shù)據(jù)正確顯示出來了。

CRUD操作

對于CRUD操作都舉一個例子,由于前面已經(jīng)介紹過findAll查詢就不在此介紹CRUD中的R了。下面就對另外三個做一個例子:
更多有關(guān)數(shù)據(jù)的操作請看Ember.js 入門指南——新建、更新、刪除記錄。

為了方便演示再增加幾個路由和模板。

ember g template users/index
ember g route users/new
ember g route users/edit

上述3個命令創(chuàng)建了三個users的子路由和子模板。

新增、更新

由于項目使用的是Ember Data,增加數(shù)據(jù)也是很簡單的,直接調(diào)用createRecord()創(chuàng)建一個record之后再調(diào)用save()方法保存到服務(wù)器。
另外新增和更新的處理方式相似,就直接寫在一個方法內(nèi)。

Ember前端處理代碼
component:user-form.js
// app/components/user-form.js
// 新增,修改user
import Ember from "ember";

export default Ember.Component.extend({
  tipInfo: null,

  actions: {
    saveOrUpdate(id, user) {
      if (id) {  //更新
        let username = this.get("model.username");
        let email = this.get("model.email");
        if (username && email) {
          this.store.findRecord("user", id).then((u) => {
            
            u.set("username", username);
            u.set("email", email);

            u.save().then(() => {
              this.set("tipInfo", "更新成功");
              // this.set("model.username", "");
              // this.set("model.email", "");
            }); 
          });
        } else {
          this.set("tipInfo", "請輸入username和email!");
        }

      } else {  //新增

        let username = this.get("model.username");
        let email = this.get("model.email");
        if (username && email) {
          this.get("store").createRecord("user", {
            username: username,
            email: email
          }).save().then(() => {
            this.set("tipInfo", "保存成功");
            this.set("model.username", "");
            this.set("model.email", "");
          }, (err) => {
            this.set("tipInfo", "保存失敗"+err);
          }); 
        } else {
          this.set("tipInfo", "請輸入username和email!");
        }
    
      }
    }
  }
});

新增和修改處理是相似的,根據(jù)id是否為空判斷是否是新增還是更新。

hbs:user-form.hbs
{{! 新增、修改都用到的表單,提出為公共部分}}

{{title}}

{{#link-to "users" class="btn btn-primary"}}返回{{/link-to}}

{{input type="text" class="form-control" id="usernameId" name="username" placeholder="username" value=model.username}}
{{input type="text" class="form-control" id="exampleInputEmail1" placeholder="Email" value=model.email}}
{{#if tipInfo}} {{/if}}
route:edit.js
// app/routes/users/edit.js
import Ember from "ember";

export default Ember.Route.extend({
  // 根據(jù)id獲取某個記錄
  model(params) {
    return this.store.findRecord("user", params.user_id);
  }
});

點擊“編輯”的時候需要根據(jù)被點擊記錄的id查詢數(shù)據(jù)詳情,并返回到編輯頁面。

new.hbs
{{! 增加數(shù)據(jù)的表單}}
{{user-form title="新增user" store=store model=model}}
edit.hbs
{{! 修改數(shù)據(jù)的表單}}
{{user-form title="修改user" store=store model=model}}

提取新增和修改這兩個模板的相同代碼為一個組件,兩個模板都調(diào)用組件。

后端處理代碼

與前端對應(yīng)的要有相應(yīng)的后端處理服務(wù),增加2個路由監(jiān)聽,一個是監(jiān)聽post提交(新增),一個是put提交(更新)。

// 處理請求 POST http://localhost:4200/users
  app.post("/api/v1/users", function(req, res) {
    
    var username = req.body.user.username;
    console.log("req.body.user.username = " + username);
    var email = req.body.user.email;
    console.log("req.body.user.email = " + email);

    // 打開數(shù)據(jù)庫連接
    pool.getConnection(function(err, conn) {  
      var queryParams = { username: username, email: email };  
      var query = conn.query("insert into user SET ?", queryParams, function(err, result) {  
          if (err) throw err;
          
          console.log("result = " + result);
          // 返回前端
          if (result) {
            res.status(200).send({
                users: {
                  id: result.insertId,
                  username: username,
                  email: email
                }
            });
          } else {  //沒有數(shù)據(jù)返回一個空的
            // 返回前端
            res.status(200).send({
                users: {
                  id: "",
                  username: "",
                  email: ""
                }
            });
          } 
          
      });
      console.log("sql: " + query.sql);
      conn.release();  //釋放連接,放回到連接池
    });
  });
    


    // 處理請求 POST http://localhost:4200/users/id  根據(jù)id更新某個數(shù)據(jù)
  app.put("/api/v1/users/:id", function(req, res) {

    console.log("更新 POST /api/v1/users/:id");
    console.log("req.params.id = " + req.params.id);
    console.log("req.body.user.username = " + req.body.user.username);
    var jsonArr = new Array();
    // 打開數(shù)據(jù)庫連接
    pool.getConnection(function(err, conn) {  
      // 參數(shù)的次序要與SQL語句的參數(shù)次序一致
      var queryParams = [ req.body.user.username, req.body.user.email, req.params.id ];
      
      var query = conn.query("UPDATE user SET username = ?, email = ? where id = ?", queryParams, function(err, results, fields) {  
          if (err) {
            console.log("更新出錯:"+err);
            throw err;
          } 

        //遍歷返回的數(shù)據(jù)并設(shè)置到返回的json對象中,通常情況下只有一個數(shù)據(jù),直接取第一個數(shù)據(jù)返回
        if (results && results.length > 0) {
          jsonArr.push({
              id: results[0].id,
              username: results[0].username,
              email: results[0].email
          });

          // 返回前端
          res.status(200).send({
              users: jsonArr
          });
        }
        //  else {  //沒有數(shù)據(jù)返回一個空的
        //   // 返回前端
        //   res.status(200).send({
        //       users: {
        //         id: "",
        //         username: "",
        //         email: ""
        //       }
        //   });
        // } 
        console.log("SQL: " + query.sql);

      });
      conn.release();  //釋放連接,放回到連接池
    });
  });

為何新增對應(yīng)的是post方法,更新對應(yīng)的是put方法,請看the rest adapter的詳細(xì)介紹(主要是第一個表格的內(nèi)容)。

簡單測試

點擊右上角的新增按鈕進(jìn)入新增界面。

進(jìn)入新增界面后輸入相應(yīng)信息(我就不做數(shù)據(jù)的格式校驗了,有需要自己校驗數(shù)據(jù)格式)。然后點擊“保存”,保存成功會有提示信息。

點擊右上角的“返回”回到主列表頁面,查看新增的數(shù)據(jù)是否保存成功。

可以看到剛剛新增的數(shù)據(jù)已經(jīng)顯示在列表上,為了進(jìn)一步驗證數(shù)據(jù)已經(jīng)保存成功,直接查看數(shù)據(jù)庫。

可以看到數(shù)據(jù)庫也已經(jīng)成功保存了剛剛新增的數(shù)據(jù)。

修改的測試方式我就不啰嗦了,點擊列表上的修改按鈕進(jìn)入修改頁面,修改后保存既可以,請自行測試。

刪除

刪除處理相比新增更加簡單,直接發(fā)送一個delete請求即可。

Ember前端處理
// app/routes/user.js
import Ember from "ember";

export default Ember.Route.extend({
  model() {
    return this.store.findAll("user");
  },
  actions: {
    // 刪除記錄
    del(id) {
      console.log("刪除記錄:" + id);
      this.get("store").findRecord("user", id).then((u) => {
          u.destroyRecord(); // => DELETE to /users/2
      });
    }
  }
});


用戶列表

{{#link-to "users.new" class="btn btn-primary"}}新增{{/link-to}}

{{#each model as |user|}} {{/each}}
# 用戶名 郵箱 操作
{{user.id}} {{user.username}} {{user.email}} {{#link-to "users.edit" user.id}}修改{{/link-to}} | 刪除

這段代碼的與前面的代碼基本一致,就是增加了刪除。

后端處理

在后端增加一個監(jiān)聽刪除的路由。

// 處理請求 DELETE http://localhost:4200/users/id 刪除記錄
  app.delete("/api/v1/users/:id", function(req, res) {

    var jsonArr = new Array();
    var id = req.params.id;
    console.log("刪除 req.params.id = " + id);

    // 打開數(shù)據(jù)庫連接
    pool.getConnection(function(err, conn) {  
      var queryParams = [ id ];  
      var query = conn.query("delete from user where id = ?", queryParams, function(err, result) {  
          if (err) throw err;

          // 返回前端
          res.status(200).send({});
      });

      console.log("sql: " + query.sql);
      conn.release();  //釋放連接,放回到連接池
    });
  });
測試刪除

測試刪除很簡單,直接在列表上點擊“刪除”按鈕即可刪除一條記錄。界面和數(shù)據(jù)庫的截圖我就不貼出來了,自己動手測試就知道了?。?/p>

數(shù)據(jù)可以正確刪除,但是,刪除之后控制臺會報如下錯誤:

找了官網(wǎng)文檔the rest adapter delete record按照官網(wǎng)的文檔處理仍然報錯!目前還沒找到好的處理方法,不知道是哪里出了問題,如果讀者知道請告訴我,謝謝。

到此CRUD操作也完成了,不足的就是在處理刪除的時候還是有點問題,目前還沒找到覺得辦法!但是總的來說對于CRUD的操作都是這么處理的,調(diào)用的方法也都是上述代碼所使用的方法。

未完待續(xù)……還差分頁沒完成。

總結(jié)

文章寫到這里已經(jīng)把我所想的內(nèi)容介紹完畢了,不知道讀者是否看明白了。其中主要理解的知識點是:

Ember Data和adapter、record、model的關(guān)系

如何自定義適配器

如何根據(jù)Ember前端請求編寫后端處理

CRUD操作

分頁處理(目前還沒整合進(jìn)來)

明白了上述幾點,本文的目的也達(dá)到了!如何有疑問歡迎給我留言,也期待著讀者能給我解答刪除報錯的問題!

文章源碼

如果有需要歡迎star或者fork學(xué)習(xí)。下面是源碼地址:

https://github.com/ubuntuvim/emberData-adapter-database,歡迎follow我,一起學(xué)習(xí)交流!我在全球最大的同性交友網(wǎng)站等你哦?。?/p> 參考網(wǎng)址

ember.js

ember-cli

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/91636.html

相關(guān)文章

  • adapter與serializer使用示例一

    摘要:由于能力有限本示例不會完全自定義適配器和序列化器,示例仍然是使用官方推薦方式,重寫或者擴展以實現(xiàn)自定適配器和序列化器。在序列化器中調(diào)用響應(yīng)請求的方法格式化返回的數(shù)據(jù)。上述就是的一個簡單實用示例。 文章來源:http://xcoding.tech/tags/Emberjs歡迎訪問源網(wǎng)站Ember Teach,Ember Teach致力于為您提供最權(quán)威、最前沿的Ember技術(shù)教程。。 ad...

    Near_Li 評論0 收藏0
  • 使用service實現(xiàn)登錄、權(quán)限控制

    摘要:就沒必要動牛刀,創(chuàng)建一個數(shù)據(jù)庫了執(zhí)行完后,在目錄下創(chuàng)建一個程序,自動植入到當(dāng)前項目中,訪問的和與訪問域名端口一致。就沒必要動牛刀,創(chuàng)建一個數(shù)據(jù)庫了本篇博文將為你介紹如何使用實現(xiàn)權(quán)限控制,我會創(chuàng)建一個簡單的登錄示例加以說明。 文章來源:http://blog.ddlisting.com 官網(wǎng)對于登錄、用戶權(quán)限的介紹只有一段簡單的說明,并沒有詳細(xì)說明如何使用service實現(xiàn)權(quán)限控制。下面...

    Aomine 評論0 收藏0
  • Day 19: EmberJS 入門指南

    摘要:在文件夾內(nèi)創(chuàng)建,內(nèi)容如下創(chuàng)建,內(nèi)容如下使用安裝依賴在的頭部加入調(diào)用命令,同時在你的默認(rèn)瀏覽器中打開。最后,我們更新下,給每個報道添加鏈接修改完畢地后,可以在瀏覽器中直接看到結(jié)果。 編者注:我們發(fā)現(xiàn)了有趣的系列文章《30天學(xué)習(xí)30種新技術(shù)》,正在翻譯,一天一篇更新,年終禮包。下面是第19天的內(nèi)容。 到目前為止,我們這一系列文章涉及了Bower、AngularJS、GruntJS、P...

    awesome23 評論0 收藏0
  • 模型高級特性,引入模型關(guān)聯(lián)關(guān)系

    摘要:創(chuàng)建模型并設(shè)置關(guān)聯(lián)關(guān)聯(lián)關(guān)系設(shè)置模型關(guān)系一個對應(yīng)多個,一個對應(yīng)多個。手動在中增加關(guān)聯(lián)關(guān)系。并且是實現(xiàn)了數(shù)據(jù)表之間的關(guān)聯(lián)關(guān)系,比如一個對應(yīng)多個,如下圖。 文章來源:模型高級特性,引入模型關(guān)聯(lián)關(guān)系 接著前面五篇: 環(huán)境搭建以及使用Ember.js創(chuàng)建第一個靜態(tài)頁面 引入計算屬性、action、動態(tài)內(nèi)容 模型,保存數(shù)據(jù)到數(shù)據(jù)庫 發(fā)布項目,加入CRUD功能 從服務(wù)器獲取數(shù)據(jù),引入組件 前言 ...

    raise_yang 評論0 收藏0
  • 模型,保存數(shù)據(jù)到數(shù)據(jù)庫

    摘要:文章來源模型,保存數(shù)據(jù)到數(shù)據(jù)庫環(huán)境搭建以及使用創(chuàng)建第一個靜態(tài)頁面引入計算屬性動態(tài)內(nèi)容繼續(xù)為讀者介紹如何使用構(gòu)建一個完整的復(fù)雜的項目。 文章來源:模型,保存數(shù)據(jù)到數(shù)據(jù)庫 環(huán)境搭建以及使用Ember.js創(chuàng)建第一個靜態(tài)頁面 引入計算屬性、action、動態(tài)內(nèi)容 繼續(xù)為讀者介紹如何使用Ember構(gòu)建一個完整的、復(fù)雜的項目。 第一個Ember.js模型 在前面兩篇中實現(xiàn)了如何獲取界面輸入的...

    paulli3 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<