摘要:由于能力有限本示例不會(huì)完全自定義適配器和序列化器,示例仍然是使用官方推薦方式,重寫或者擴(kuò)展以實(shí)現(xiàn)自定適配器和序列化器。在序列化器中調(diào)用響應(yīng)請(qǐng)求的方法格式化返回的數(shù)據(jù)。上述就是的一個(gè)簡(jiǎn)單實(shí)用示例。
文章來源:http://xcoding.tech/tags/Emberjs
歡迎訪問源網(wǎng)站Ember Teach,Ember Teach致力于為您提供最權(quán)威、最前沿的Ember技術(shù)教程。。
adapter與serializer相對(duì)來說是比較高級(jí)的內(nèi)容。但是也是非常常用的一個(gè)組件,最常用到這兩個(gè)組件的就是Ember Data。Ember Data已經(jīng)實(shí)現(xiàn)了這兩個(gè)組件,并且提供了非常豐富的API,如果要自定義適配器和序列化器一般都是擴(kuò)展或者是重寫JSONAPIAdapter,這也是官方建議的方式,JSONAPIAdapter是遵循json api規(guī)范的適配器,主要表現(xiàn)在數(shù)據(jù)的交換格式必須遵循JSONAPI規(guī)范。當(dāng)然如果你想完全重新實(shí)現(xiàn)一套自定義的適配器和序列化器也是可以的,官方建議是基于Adapter做擴(kuò)展。由于能力有限本示例不會(huì)完全自定義適配器和序列化器,示例仍然是使用官方推薦方式,重寫或者擴(kuò)展JSONAPIAdapter以實(shí)現(xiàn)自定適配器和序列化器。
那么我們?yōu)楹涡枰远x適配器呢?很明顯的一個(gè)原因就是Ember.js并沒有提供數(shù)據(jù)存儲(chǔ)方案,Ember目前更多的只是一個(gè)前端的MVC框架,數(shù)據(jù)的存儲(chǔ)服務(wù)還是要開發(fā)者提供,目前比較流行的做法是使用谷歌的Firebase,F(xiàn)irebase是一個(gè)實(shí)時(shí)更新數(shù)據(jù)的后端服務(wù),國(guó)內(nèi)也有類似的跟隨者(野狗)但是目前野狗還沒有Ember的適配器,相反Firebase提供了完備的Ember適配器,使用起來非常方便,而且還提供了免費(fèi)的服務(wù)??梢哉f除了網(wǎng)速比較慢之外是非常適合做Ember的數(shù)據(jù)服務(wù)的。但是比較遺憾的是我們?cè)谔斐瘍?nèi),你懂滴,谷歌的東西在我們這個(gè)國(guó)度要使用還是不怎么順暢的。那么既然不能使用現(xiàn)有的輪子那么我們只能使用自己的后端數(shù)據(jù)服務(wù)了,此時(shí)就必須要自定義適配器了(我們能直接使用Firebase的原因就是Firebase提供完美的適配器,不需要開發(fā)者去開發(fā),直接使用即可)。
Ember所推崇是“約定由于配置”,所有Ember默認(rèn)了很多規(guī)則,自然適配器和序列化器也不例外,所以本例子程序會(huì)包括兩個(gè)方面的東西,一個(gè)是Ember項(xiàng)目本身;另一個(gè)是為Ember項(xiàng)目提供服務(wù)器的后端數(shù)據(jù)庫(kù)以及數(shù)據(jù)庫(kù)處理程序。
主要軟件說明MongoDB
NodeJS
Mongoose
json api服務(wù)端
Ember CLI
上述軟件的安裝與配置請(qǐng)自行根據(jù)各自官網(wǎng)文檔介紹安裝配置,如果你想使用其他數(shù)據(jù)庫(kù)也是可以的,但是處理起來可能沒有MongoDB那么方便,如果你看過jsonapi規(guī)范就知道,jsonapi相對(duì)于普通的json數(shù)據(jù)還是有挺大差別的,如果是使用其他數(shù)據(jù)庫(kù)(比如MySQL)處理起來可能稍微麻煩一些,另外一個(gè)很重要的原因就是json API插件大部分都是node版的,說了這么多其實(shí)就是想把服務(wù)器返回的數(shù)據(jù)格式格式化為jsonapi規(guī)范,否則其他格式的數(shù)據(jù)JSONAPIAdapter適配器是無(wú)法識(shí)別的,會(huì)報(bào)錯(cuò)。
再啰嗦幾句:一個(gè)APP之所以能與后端服務(wù)良好交互,其他交互的數(shù)據(jù)格式都是比較固定的,Ember也不例外,因?yàn)镋mber Data所接受的數(shù)據(jù)格式是jsonapi,所以我們的后端服務(wù)返回的數(shù)據(jù)格式必須符合jsonapi規(guī)范,當(dāng)然如果你不是使用Ember Data,你使用的是其他的數(shù)據(jù)持久化庫(kù)也是可以的,那么相對(duì)的你的的后端數(shù)據(jù)服務(wù)返回的數(shù)據(jù)格式就要跟你的持久化庫(kù)相匹配就可以了,如果你想使用其他的持久化庫(kù)你可以參考jsonapi client libraries,上面提供了各個(gè)語(yǔ)言的持久化庫(kù)。
搭建項(xiàng)目言歸正傳,下面結(jié)合一個(gè)小例子講解如何去自定義適配器去連接到自己的數(shù)據(jù)庫(kù),并把數(shù)據(jù)持久化到數(shù)據(jù)庫(kù)中。
使用Ember CLI創(chuàng)建一個(gè)普通的Ember項(xiàng)目,命令如下:
ember new ember-adapter-serializer cd ember-adapter-serializer ember s
啟動(dòng)項(xiàng)目后預(yù)覽http://localhost:4200,可以看到Ember常規(guī)的歡迎信息,說明項(xiàng)目創(chuàng)建成功。
創(chuàng)建路由、模型、模板仍然是使用Ember CLI命令創(chuàng)建演示示例所需的路由、模型、模板文件,本示例會(huì)構(gòu)建一個(gè)簡(jiǎn)單的博客項(xiàng)目,目的主要是為了使項(xiàng)目盡量包含模型的一對(duì)一、一對(duì)多、多對(duì)多關(guān)系,這些關(guān)系是一個(gè)適配器比較關(guān)鍵的東西(簡(jiǎn)單理解,其實(shí)適配器就像MVC項(xiàng)目中的DAO層,專門做數(shù)據(jù)處理的)。
創(chuàng)建命令如下:
ember g route users ember g model user ember g route users/list ember g route users/new ember g route users/edit ember g route posts ember g model post ember g route tags ember g model tag ember g route comments ember g model comment
后續(xù)使用到其他的文件再創(chuàng)建。
模型處理模型的處理主要是設(shè)置模型的屬性以及模型之間的關(guān)系,在本例子中定義了3個(gè)模型:user、post、tag、comment。他們的關(guān)系如下:
user與post是一對(duì)多的關(guān)系
user與comment是一對(duì)多的關(guān)系
post與comment也是一對(duì)多的關(guān)系
post與tag是多對(duì)多關(guān)系
各個(gè)模型代碼如下:
user// app/models/user.js import Model from "ember-data/model"; import attr from "ember-data/attr"; import { belongsTo,hasMany } from "ember-data/relationships"; export default Model.extend({ name: attr("string"), password: attr("string"), birth: attr("string"), addr: attr("string"), //一對(duì)多關(guān)系,一的一方設(shè)置hasMay,多的一方設(shè)置belongsTo comments: hasMany("comment"), posts: hasMany("post") });post
// app/models/post.js import Model from "ember-data/model"; import attr from "ember-data/attr"; import { belongsTo,hasMany } from "ember-data/relationships"; export default Model.extend({ title: attr("string"), publicDate: attr("date"), content: attr("string"), user: belongsTo("user"), //一對(duì)多關(guān)系,多的一方使用belongsTo comments: hasMany("comment"), tags: hasMany("tag") });comment
// app/models/comment.js import Model from "ember-data/model"; import attr from "ember-data/attr"; import { belongsTo,hasMany } from "ember-data/relationships"; export default Model.extend({ title: attr("string"), publicDate: attr("date"), content: attr("string"), user: belongsTo("user"), //一對(duì)多關(guān)系,多的一方使用belongsTo post: belongsTo("post") });tag
// app/models/tag.js import Model from "ember-data/model"; import attr from "ember-data/attr"; import { belongsTo,hasMany } from "ember-data/relationships"; export default Model.extend({ title: attr("string"), posts: hasMany("post") });
創(chuàng)建完模型之后,先從user開始,簡(jiǎn)單做一個(gè)列表顯示所有user,并在在列表頁(yè)面可以新增、修改、刪除user,實(shí)現(xiàn)最常見的CRUD操作。在實(shí)現(xiàn)的過程中插入adapter和serializer的內(nèi)容。
用戶列表用戶列表頁(yè)面也是很簡(jiǎn)單的,就一個(gè)表格,其中引入了bootstrap樣式。有關(guān)怎么引入請(qǐng)自己網(wǎng)上找答案吧。
列表模板{{! app/templates/users/list.hbs 用戶列表}}列表路由配置{{#link-to "users.new" class="btn btn-success"}}新增{{/link-to}}
{{#each model as |user|}} 用戶名 生日 地址 操作 {{/each}} {{user.name}} {{user.birth}} {{user.addr}} {{#link-to "users.edit" user.id}}修改{{/link-to}} | 刪除
import Ember from "ember"; export default Ember.Route.extend({ model() { return this.store.findAll("user"); } });
列表的路由也很簡(jiǎn)單,直接獲取所有的user記錄,并返回到模板中,在模板中便利出每個(gè)記錄。
待項(xiàng)目重啟完成,直接預(yù)覽http://localhost:4200/users/list,可以看到頁(yè)面上什么也沒有顯示,打開瀏覽器控制臺(tái)可以看到如下錯(cuò)誤:
很顯然我們的項(xiàng)目中確實(shí)沒有提供請(qǐng)求http://localhost:4200/users的后端服務(wù),而且項(xiàng)目也沒有鏈接其他任何數(shù)據(jù)服務(wù)(比如Firebase),那么如何讓Ember項(xiàng)目鏈接到我自己的數(shù)據(jù)庫(kù)上呢?
在此,先引入數(shù)據(jù)服務(wù)程序,前面介紹過,本例子使用Mongodb。服務(wù)端程序請(qǐng)看adapter-serializer-server,對(duì)于服務(wù)端的內(nèi)容我就部過多介紹,你只需要知道這個(gè)服務(wù)程序可以接受、返回的數(shù)據(jù)格式是jsonapi就行了。然后啟動(dòng)后端服務(wù)程序。
那么如何讓Ember項(xiàng)目鏈接到我的后端服務(wù)呢??很簡(jiǎn)單,只需要重寫適配器的一個(gè)屬性即可。下面使用Ember CLI名稱創(chuàng)建一個(gè)適配器。
ember g adapter application
適配器創(chuàng)建完畢之后,我們直接在適配器中接入自己的后端服務(wù)。代碼如下:
// app/adapters/application.js import JSONAPIAdapter from "ember-data/adapters/json-api"; export default JSONAPIAdapter.extend({ host: "http://localhost:3000" });
http://localhost:3000是adapter-serializer-server啟動(dòng)后提供服務(wù)的url。項(xiàng)目啟動(dòng)完畢后可以看到瀏覽器控制臺(tái)的錯(cuò)誤消失了!并且在“NetWork”標(biāo)簽下可以看到有一個(gè)請(qǐng)求http://localhost:3000/users點(diǎn)擊這個(gè)請(qǐng)求,查看請(qǐng)求的“Response”可以看到返回的數(shù)據(jù),比如下面的數(shù)據(jù)格式:
{ "links": { "self": "http://localhost:3000/users" }, "data": [ { "id": "5753d7090280777c2381a0dd", "type": "users", "attributes": { "name": "日期修改333", "password": "11", "addr": "地址地址地址地址", "birth": "2016-06-04T00:00:00.000Z" }, "links": { "self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd" }, "relationships": { "comments": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd/relationships/comments" } }, "posts": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/5753d7090280777c2381a0dd/relationships/posts" } } } }, { "id": "5753d74a840db09d2352608a", "type": "users", "attributes": { "name": "解決了跨域問題", "password": "123132", "addr": "范文芳啊的份水電費(fèi) 測(cè)試服我飛" }, "links": { "self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a" }, "relationships": { "comments": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a/relationships/comments" } }, "posts": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/5753d74a840db09d2352608a/relationships/posts" } } } }, { "id": "57545597840db09d2352608b", "type": "users", "attributes": { "name": "測(cè)試日期控件", "password": "123123", "addr": "適配器和序列化器示例" }, "links": { "self": "http://127.0.0.1:3000/users/57545597840db09d2352608b" }, "relationships": { "comments": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/57545597840db09d2352608b/relationships/comments" } }, "posts": { "data": [], "links": { "self": "http://127.0.0.1:3000/users/57545597840db09d2352608b/relationships/posts" } } } } ] }
由于我項(xiàng)目已經(jīng)有了3條數(shù)據(jù)了,所以跟你的可能有些許不同,但是數(shù)據(jù)的格式是一致的。這個(gè)數(shù)據(jù)的格式是遵循jsonapi規(guī)范的。
上述代碼所演示的是自定義適配器最最常用的一個(gè)功能,如果你后端返回的數(shù)據(jù)是完全遵循jsonapi規(guī)范的幾乎不需要再做其他任何修改了。這樣就已經(jīng)完成自定義適配器的工作了!但是既然在此特意介紹適配器和序列化器當(dāng)然不會(huì)只是介紹這一個(gè)屬性host就完了,后面將陸陸續(xù)續(xù)介紹其他的屬性,以及如何使用serializer。
繼續(xù)完成user模塊。
新增user user模板{{! app/templates/users/new.hbs 新增user}}user路由
直接在model回調(diào)中返回一個(gè)空的實(shí)例對(duì)象。方便保存。
// app/routes/users/new.js import Ember from "ember"; export default Ember.Route.extend({ model() { return this.store.createRecord("user"); }, actions: { saveUser(user) { user.save().then(() => { this.transitionTo("users.list");// 保存成功轉(zhuǎn)到列表頁(yè)面 }); } } });修改user user模板
{{! app/templates/users/edit.hbs 修改user}}user路由
在修改的方法中先調(diào)用findRecord方法查詢出被修改的數(shù)據(jù),然后更新修改的屬性,再調(diào)用save方法保存修改的內(nèi)容。
// 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); }, actions: { updateUser(user) { this.store.findRecord("user", user.get("id")).then((u) => { u.set("name", user.get("name")); u.set("addr", user.get("addr")); u.set("birth", user.get("birth")); u.set("addr", user.get("addr")); u.save(); //保存修改的屬性值 }); this.transitionTo("users.list"); //轉(zhuǎn)到列表頁(yè)面 } } });
由于新增、修改user模板都用到供一個(gè)表單,提取到一個(gè)組件中。
ember g component user-form
文件代碼就不貼出來了,有需要請(qǐng)點(diǎn)擊查看github代碼。然后在組件類中初始化了一個(gè)日期控件bootstrap-datepicker,插件直接在app/index.html中引入了,下面是組件類代碼:
// app/components/user-form.js import Ember from "ember"; export default Ember.Component.extend({ didInsertElement() { this._super(...arguments); //記得調(diào)用父類的構(gòu)造方法 //初始化日期控件 Ember.$(".datepicker").datepicker({format:"yyyy-mm-dd", autoclose: true}); } });
user列表、新增user、修改user界面效果如下截圖:
到此實(shí)現(xiàn)了類似使用Firebase的數(shù)據(jù)存儲(chǔ)功能,可以正確保存數(shù)據(jù)到自己的數(shù)據(jù)庫(kù)中??梢钥隙ǖ氖菙?shù)據(jù)已經(jīng)正確保存到我的MongoDB中,我就不再截圖了!對(duì)象的CRUD功能已經(jīng)實(shí)現(xiàn),后續(xù)我就不再介紹post、comment、tag的CRUD了,后續(xù)著重介紹適配器、序列化器的其他屬性以及模型之間的關(guān)聯(lián)關(guān)系(比如一對(duì)多、多對(duì)多)。
如果你認(rèn)真看前面的第一個(gè)截圖你會(huì)發(fā)現(xiàn)列表上顯示的時(shí)間格式不友好,不是我們所習(xí)慣看的時(shí)間格式,那么如何處理呢?格式化時(shí)間的方式有很多,可以自定義Ember helper格式化時(shí)間,也可以定義模型user的屬性birth為date類型,在此我特意定義為了string是為了演示serializer的使用。我們可以在自定義的serializer中格式化返回的數(shù)據(jù)。下面首先創(chuàng)建serializer。
ember g serializer application
在序列化器中調(diào)用響應(yīng)請(qǐng)求的方法normalizeResponse格式化返回的數(shù)據(jù)。代碼如下:
// app/serializers/application.js import JSONAPISerializer from "ember-data/serializers/json-api"; export default JSONAPISerializer.extend({ // 此方法響應(yīng)請(qǐng)求的時(shí)候執(zhí)行 normalizeResponse(store, primaryModelClass, payload, id, requestType) { // 格式化birth的時(shí)間格式 //默認(rèn)顯示的時(shí)間格式為 2016-06-09T00:00:00.000Z ,簡(jiǎn)單處理直接截取前面的10位 // 只是為了演示方法normalizeResponse的使用,實(shí)際項(xiàng)目中不推薦這樣的用法,因?yàn)樾枰闅v每個(gè)數(shù)據(jù),效率不好 payload.data.forEach(function(item, index) { var oldDate = item.attributes.birth; if (oldDate) { oldDate = oldDate.substring(0, 10); } item.attributes.birth = oldDate; oldDate = null; }); return this._super(...arguments); } // 此方法發(fā)送請(qǐng)求的時(shí)候回執(zhí)行 // serialize(snapshot, options) { // // } });
但是實(shí)際使用過程中不推薦使用這種方式格式化數(shù)據(jù),除非是不得已,因?yàn)樾枰闅v每個(gè)記錄去修改屬性的值,如果數(shù)據(jù)量大影響效率,最好的方式是自定義helper在模板上格式化。把格式化的操作放到顯示數(shù)據(jù)的時(shí)候。
上述就是serializer的一個(gè)簡(jiǎn)單實(shí)用示例。
adapter和serializer內(nèi)容比較多,分為2篇介紹,下一篇我回在本篇的基礎(chǔ)上逐個(gè)介紹adapter和serializer的常用屬性、方法的使用。
adapter與serializer使用下篇adapter與serializer使用實(shí)例二
項(xiàng)目源碼:https://github.com/ubuntuvim/ember-adapter-serializer
后臺(tái)源碼:https://github.com/ubuntuvim/adapter-serializer-server
有疑問歡迎在下方評(píng)論區(qū)給我留言,我會(huì)盡快為你解答,如果你覺得本文能給你幫助,或者覺得博主寫作辛苦也歡迎點(diǎn)擊右上角“為博主充電”給我打賞,你的肯定對(duì)我來說是最大的動(dòng)力。O(∩_∩)O哈哈~
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86351.html
摘要:返回?cái)?shù)據(jù)請(qǐng)求流程后端返回的數(shù)據(jù)首先也會(huì)經(jīng)過上面的處理其次經(jīng)過返回進(jìn)將數(shù)據(jù)存儲(chǔ)起來后返回請(qǐng)求數(shù)據(jù)的地方。至此一個(gè)請(qǐng)求后端數(shù)據(jù)的請(qǐng)求的流程就到此結(jié)束了。例如等以及官方推薦最少要復(fù)寫的方法 Emberjs 如何與后端服務(wù)進(jìn)行交互 @[toc] 一般發(fā)送請(qǐng)求流程 首先來看這張圖: showImg(https://segmentfault.com/img/bVCzJn?w=339&h=521...
摘要:目前打算本項(xiàng)目使用種數(shù)據(jù)交互方式一種是,一種是。要理解后端服務(wù)的關(guān)系我們從他們各自的概念入手。創(chuàng)建服務(wù)端如何在項(xiàng)目中創(chuàng)建服務(wù)端程序呢提供了創(chuàng)建的命令。 文章來源:Ember Teach 本項(xiàng)目講解如何使用adapter、EmberData以及怎么連接到本地?cái)?shù)據(jù)庫(kù)。 項(xiàng)目簡(jiǎn)介 主要內(nèi)容 適配器使用 如何持久化數(shù)據(jù)到本地?cái)?shù)據(jù)庫(kù) 簡(jiǎn)單的后端服務(wù) 最近經(jīng)常有初學(xué)的開發(fā)者請(qǐng)教有關(guān)Adapte...
摘要:就沒必要?jiǎng)优5?,?chuàng)建一個(gè)數(shù)據(jù)庫(kù)了執(zhí)行完后,在目錄下創(chuàng)建一個(gè)程序,自動(dòng)植入到當(dāng)前項(xiàng)目中,訪問的和與訪問域名端口一致。就沒必要?jiǎng)优5叮瑒?chuàng)建一個(gè)數(shù)據(jù)庫(kù)了本篇博文將為你介紹如何使用實(shí)現(xiàn)權(quán)限控制,我會(huì)創(chuàng)建一個(gè)簡(jiǎn)單的登錄示例加以說明。 文章來源:http://blog.ddlisting.com 官網(wǎng)對(duì)于登錄、用戶權(quán)限的介紹只有一段簡(jiǎn)單的說明,并沒有詳細(xì)說明如何使用service實(shí)現(xiàn)權(quán)限控制。下面...
摘要:遠(yuǎn)程調(diào)用開篇目標(biāo)介紹之后解讀遠(yuǎn)程調(diào)用模塊的內(nèi)容如何編排介紹中的包結(jié)構(gòu)設(shè)計(jì)以及最外層的的源碼解析。十該類就是遠(yuǎn)程調(diào)用的上下文,貫穿著整個(gè)調(diào)用,例如調(diào)用,然后調(diào)用。十五該類是系統(tǒng)上下文,僅供內(nèi)部使用。 遠(yuǎn)程調(diào)用——開篇 目標(biāo):介紹之后解讀遠(yuǎn)程調(diào)用模塊的內(nèi)容如何編排、介紹dubbo-rpc-api中的包結(jié)構(gòu)設(shè)計(jì)以及最外層的的源碼解析。 前言 最近我面臨著一個(gè)選擇,因?yàn)閐ubbo 2.7.0-...
閱讀 3615·2021-09-08 10:46
閱讀 1237·2019-08-30 13:17
閱讀 2425·2019-08-30 13:05
閱讀 1253·2019-08-29 15:29
閱讀 2935·2019-08-29 11:31
閱讀 589·2019-08-26 12:13
閱讀 1604·2019-08-26 11:42
閱讀 1974·2019-08-23 18:37