文章来源:Ember Teachjavascript
本项目讲解如何使用adapter、EmberData以及怎么链接到本地数据库。html
适配器使用前端
如何持久化数据到本地数据库java
简单的后端服务node
最近常常有初学的开发者请教有关Adapter
或者Ember Data
的问题。官方教程中讲到这两个内容的是Model这一章节。本文中介绍到的内容大部分是由这一章来的,若是有不妥请看原文或者给我留言。mysql
注意:本文是基于v2.6.0讲解。git
MySQLgithub
body-parsersql
用到的软件、插件都是有关后端服务的,mysql-node
用于链接、操做MySQL数据库。后端服务是用node写的因此也用node项目的插件链接、操做数据库了,有关如何使用node操做MySQL的信息请看这篇文章[nodejs链接MySQL,作简单的CRUD
](http://blog.ddlisting.com/201...。若是你的后端是其余语言写只须要保证你后端返回的数据格式或者个人后端返回的数据格式一致就好了。目前打算本项目使用2种数据交互方式:一种是jsonapi,一种是restapi。
项目的搭建就再也不费口舌了,Ember Teach已经有不少博文介绍过了。
若是你想运行本项目请按照下面的步骤操做:
下载代码到本地 git clone https://github.com/ubuntuvim/emberData-adapter-database
进入项目目录 cd emberData-adapter-database
安装npm依赖包 npm install
安装bower依赖包 bower install
在项目目录下执行命令 ember server
运行项目。
待项目启动完毕,在浏览器打开http://localhost:4200。
执行命令编译、打包项目 ember build --environment production
命令执行完毕会在dist
目录下获得项目打包后的文件。
把打包后的dist
目录下的全部文件复制到服务器应用目录下运行便可(好比tomcat服务器则放到webapps
目录下)。
简单起见我就作一个页面就好了,我但愿作出的效果是使用自定义的适配器获取到本地MySQL数据库的数据并分页展现。
使用ember-cli命令建立文件。
ember g route users ember g model user username:string email:string ember g adapter application
目前暂时只用到这几个文件,后续可能还有其余的用到在建立。ember g model user username:string email:string
的做用是建立模型的同时建立2个属性,而且属性都指定为string
类型。
说了一大堆废话下面开始正题。要理解adapter
、ember data
、后端服务的关系咱们从他们各自的概念入手。首先咱们先理清楚他们之间的关系而后在动手实践。理论老是繁琐的可是也是最重要的。
========================= 华丽的分割线 =========================
注:图片来自官方文档
注意观察上图的结构。
APP(通常是从route
、controller
或者component
发请求)请求数据。
请求并无直接发送到后端服务而是先在store
(ember data其实就是一个store
)缓存中查找,ember之因此能实现动态更新模板数据也是由于有了store
。
若是请求的数据存在在store
中,则直接返回到route
、controller
或者component
;若是在store
中没有发现请求的数据,因此请求的数据是首次,数据还未缓存到store
中,则请求继续往下到了apdater
层。
在adapter
中,adapter
会根据请求的调用方法构建出对应的URL。好比在route
、controller
或者component
中执行方法findRecord('user', 1)
,此方法做用是查询id为1的user数据。适配器构建出来的URL为: http://domain/user/1,而后发请求到后端。
适配器会对比后端接受的数据格式与ember data发送的数据格式,若是不一致须要在适配器的``方法中格式化发送的数据格式。请求通过适配器构建获得URL后发送到后端服务,后端服务根据URL请求查询数据库而后格式化数据格式返回到适配器。
适配器根据获得的数据和ember data所接受的数据格式匹配,若是格式不一致须要在适配器的``方法中格式化后端返回的数据。
通过适配器以后数据转到ember data(store
)中,首先缓存到store
中,而后返回到调用处(route
、controller
、component
)
数据请求完毕
注意:findRecord('user', 1)
方法执行过程,请求的findRecord('user', 1)
方法会在Ember Data内部解析为find
方法,find
方法会首先在store
缓存中查数据,若是没有则会流转到adapter
中组装URL并格式化请求数据,而后发送到后端服务。
从图中看到从适配器返回的数据是promise因此调用findRecord
方法获取数据的时候须要then()
。同时可见这是个移步请求,只有promises执行成功才能获得数据。也就是说若是考虑周全的话还须要在findRecord
的时候处理promises执行失败的状况。
另外若是你想跳过store
不须要这层缓存也是能够的。会能够这样作:store.findRecord(type, id, { reload: true })
使用reload
属性设置为true
让每次请求都跳过store
直接发送请求到后端,对于实时性要求高的APP则须要这样处理。
介绍完架构以后将追个介绍其中的每一个主要的功能特性。
须要说明的是:Models
, records
, adapters
以及store
都是Ember Data最核心的东西,他们是包含的关系,只要使用了Ember Data才能使用model
、store
功能。有些初学者总是问这几个东西的关联,但愿看到这里的同窗不要在提这样的问题了!!=^=
Ember Data是Ember.js很是重要的一块,提供了几乎全部操做数据的API,详细请看EMBER-DATA MODULE。固然,若是你不想使用Ember Data也是能够的,那么你的程序直接使用Ajax与后台交互也是能够的,或者说你使用其余相似Ember Data的插件也行。Ember Data在MVC模式中属于M层的东西,没有这层也并不影响到整个APP!
若是你不使用Ember Data,在这里提供一个简单的方案供参考。
若是你想获取后端数据并显示数据到组件上(模板调用组件),你能够像下面的代码这样处理:
// app/components/list-of-drafts.js export default Ember.Component.extend({ willRender() { $.getJSON('/drafts').then(data => { this.set('drafts', data); }); } });
这里不一样过Ember Data,天然也就没有调用Ember Data提供的方法(好比,findAll、findRecord),而是直接发Ajax请求,获得数据到设置到对象drafts
中,而后在模板上显示数据。
<!-- app/templates/components/list-of-drafts.hbs --> <ul> {{#each drafts key="id" as |draft|}} <li>{{draft.title}}</li> {{/each}} </ul>
这样处理是没问题的,可是当数据改变的可能不能当即在模板上更新,由于这里没法使用store
天然也就没法像计算属性那样当数据有变就当即更新模板。另外一个问题是当你的请求不少的时候你须要写不少这样的方法,代码复用性也比较差。
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其实就是与后端数据表对应的实体类(借用java中的说法),一般咱们的model类的定义是与后端数据表对应的,最多见的就是model属性的定义,建议属性名和数据表字段名一致而且使用驼峰式命名规范。
model之间还能够定义单向或者双向的一对1、一对多和多对多关系,这个与数据表之间的关系定义是类似的。好比下面的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命令建立:
ember g model person
上面代码建立了一个简单的model,而且包含了3个属性,一个是string
类型一个是date
类型,那么第三个属性是什么了??是id
,Ember会默认为每一个model增长一个属性id
,开发者不须要手动去定义这个属性,而且若是你是手动在model类中定义这个属性会报错的!!那么对应后端的服务也应该有一个person表,而且表里也有三个字段,它们是firstName
、birthday
以及id
。
更多有关model之间关系的介绍不行本文的重点,请看第六章 模型的详细介绍。
有了model以后程序要使用model类必需要实例化,实例化的model称为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
andID
.
简单讲record就是一个包含数据的model实例。说白了就是一个JSON对象(虽然这样的说法不是很正确,可是能够反映出这是一个什么样的对象结构)。
好比下面的代码:
this.get('store').findRecord('person', 1); // => { id: 1, name: 'steve-buscemi' }
执行完方法findRecord
后返回的就是一个model实例也就是一个record。这个record包含了数据{ id: 1, name: 'steve-buscemi' }
。
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.
适配器,顾名思义!做用就是作适配工做的,保存转换数据格式、定义交互的URL前缀、构建URL等等。在前面体系结构已经详细介绍过,不在赘述。
缓存在Ember中是很是重要的,可是有一点须要注意的是不要把太多数据缓存到store中,数据量太大浏览器受不了!缓存的做用是很是明显的,前面也介绍了他的做用,特别是在请求数据的时候,若是能在缓存中获取的则当即返回到调用处,只有在缓存中查不到的数据才发请求到服务端,一般是第一次获取的数据的时候缓存没有则须要发请求到服务端。也正是有了缓存Ember才能快速把数据的变化响应到模板上。
到此主要核心的概念介绍完毕了,不算多,可是认真看下来仍是颇有益的!!
下面接着是如何实践了……
本例子使用的是MySQL数据库,有关数据库的安装以及使用不在本文讲解范围,请自行学习!
怎么建表我也不说了,下面直接贴建表的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;
建立一个名为user
的数据表。
如何在ember项目中建立服务端程序呢?ember提供了建立的命令。
ember g server
建立完毕以后再按照开始介绍的依赖插件。
npm install mysql-node npm install body-parser npm install supervisor
建立的是一个node服务端程序,运行的端口也是4200
,不须要另外手动去启动node服务,只要ember项目运行了会自动运行起来的。
到此全部的原料都准备好了,下面验证一下项目是否还能正常运行。启动项目,而后在浏览器打开http://localhost:4200。还能看到Welcome to Ember说明是成功的!
有了原料开始作菜吧!!!
为了避免使服务端和Ember请求URL冲突修改了URL的默认方式,修改config/environment.js
的第8行代码为以下:
locationType: 'hash',
auto
改成hash
。访问Ember项目的URL则须要注意:http://localhost:4200/users改成http://localhost:4200/#/users。增长一个#
号。
首先简单列出数据库数据。
<!-- app/templates/users.hbs --> <h1>用户列表</h1> <table class="table table-striped table-hover"> <thead> <tr> <th> # </th> <th> 用户名 </th> <th> 邮箱 </th> </tr> </thead> <tbody> {{#each model as |user|}} <tr> <td> {{user.id}} </td> <td> {{user.username}} </td> <td> {{user.email}} </td> </tr> {{/each}} </tbody> </table>
// app/routes/users.js import Ember from 'ember'; export default Ember.Route.extend({ model() { return this.store.findAll('user'); } });
目前项目还没链接到任何数据库,也没有使用自定义的适配器,若是直接执行http://localhost:4200/#/users能够在控制台看到是会报错的。那么下一步该如何处理呢??
RESTAdapter
先从适配器下手!在前面已经建立好了适配器,若是是2.0以后的项目默认会建立JSONAPIAdapter
这个适配器所接收、发送的数据格式都必须符合jsonapi规范,不然会报错,没法正常完成数据的交互。不过为了简便咱们先不使用这个适配器,改用另外一个简单的适配器RESTAdapter
,这个适配器不是须要遵循jsonapi规范,只要本身约定好先后端的数据格式便可。
// app/adapters/application.js // import JSONAPIAdapter from 'ember-data/adapters/json-api'; import DS from 'ember-data'; export default DS.RESTAdapter.extend({ });
手动修改好以后的适配器还不能起做用,这个适配器并无链接到任何的后端服务,若是你想链接到你的服务上须要使用属性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,在控制台仍然看到前面的错误,截图以下:
为什么仍是错误呢?若是能看到错误说明你的程序是正确,到目前为止还没提供任何的后端服务,虽然前面使用ember g server
建立了node后端服务,可是并无针对每一个请求作处理。当你访问路由user
在进入回到model
时候会发送请求获取全部模型user
数据,请求首选转到Ember Data(store),可是在store中并无,而后请求继续转到适配器RESTAdapter
,适配器会构建URL获得GET
请求http://localhost:4200/users
,至因而如何构建URL的请看build url method。这个请求能够在报错的信息中看到。可是为什么会报错呢?很正常,由于个人后端服务并没响应这个请求。下面针对这个请求作处理。
修改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')); // 对象转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' } ] }); }); };
在服务端增长了一个node请求处理,拦截/users
这个请求。对于express不是本文的重点,请自行学习,网址expressjs.com。若是你使用的是其余语言的服务端程序,那么你只须要返回的json格式为:{"modelName":[{"id":1,"属性名":"属性值","属性名2":"属性值2"},{"id":2,"属性名3":"属性值3","属性名4":"属性4"}]}
,只须要格式正确适配器就能正确解析返回的数据。
另外再多介绍一个属性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也须要作相应的处理,须要在拦截的请求上加前缀,好比下面的代码。
// 处理请求 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。那么这样作的好处是什么呢?当你的后端的API更新的时候这个设置是很是有用的,只须要设置命名前缀就能适应不用版本的API。
项目重启以后,再次进入到路由users
能够看到返回的3条数据。以下截图:
到此,我想你应该知道个大概了吧!!更多有关适配器的介绍请看下面的2篇博文:
JSONAPIAdapter
使用JSONAPIAdapter
适配器和使用RESTAdapter
适配器有何不一样呢?我以为最重要的一点是:数据规范。JSONAPIAdapter
适配器要求交互的数据格式必须遵循jsonapi规范,不然是不能完成数据交互的。要求高了相应的你的处理代码也相应的要复杂。下面咱们改用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
。若是你不修改后端的服务那么控制台能够看到报错信息。
从截图当中能够清楚地看到报错出来的错误,must return a valid JSON API document
必须是一个有效jsonapi文档。要修复好这个错误也很简单,只须要滚吧后端服务返回的数据格式改为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' // } // ] // }); // 构建jsonapi对象 var input = { data: [ { id: '1', type: 'user', //对应前端程序中模型的名字 attributes: { // 模型中的属性键值对 username: 'ubuntuvim', property: true, email: '123@qq.com', property: true } }, { id: '2', type: 'user', //对应前端程序中模型的名字 attributes: { // 模型中的属性键值对 username: 'ddlisting.com', property: true, email: '3333@qq.com', property: true } }, { id: '3', type: 'user', //对应前端程序中模型的名字 attributes: { // 模型中的属性键值对 username: 'www.ddlising.com', property: true, email: '1527254027@qq.com', property: true } } ] }; res.status(200).send(JSON.stringify(input)); });
注:为了构建jsonapi对象更加简便另外在安装一个插件: npm install jsonapi-parse
。安装完毕后手动关闭再重启项目。而后再次进入路由users
能够看到与前面的结果同样,正确了显示后端返回的数据。
到此,我相信读者应该能明白这两个适配器之间的差异了!须要注意的是Ember.js2.0
版本以后JSONAPIAdapter
做为默认的适配器,也就是说日常若是你没有自定义任何适配器那么Ember Data会默认使用的是JSONAPIAdapter
适配器。因此若是你没有使用其余的适配器那么你的后端返回的数据格式必须是遵循jsonapi规范的。另外在路由users.js
中使用到Ember Data提供的方法findAll('modelName')
,我想从中你也应该明白了Ember Data是何等重要了吧
看到这里不知道读者是否已经明白适配器和后端服务的关联关系?若是有疑问请给我留言。
文中所说的后端就是个人node程序(放在server
目录下),前端就是个人Ember.js项目。
下面就是再结合数据库。
其实到这步加不加数据库已经不那么重要了!重要把服务端返回的数据改为从数据库读取就完了。我就简单讲解了。
链接MySQL的工做交给前面已经安装好的node-mysql
,若是还没安装请执行命令npm install mysqljs/mysql
进行安装。继续修改后端服务代码server/index.js
。
module.exports = function(app) { // 与以前的内容不变 // // 引入MySQL模块 var mysql = require('mysql'); // 获取链接对象 var conn = mysql.createConnection({ host: 'localhost', user: 'root', password: '', // 开启debug,能够在启动ember项目的终端看到更多详细的信息 database: 'test' }); // 处理请求 http://localhost:4200/user app.get('/api/v1/users', function(req, res) { var jsonArr = new Array(); // 打开数据库链接 conn.connect(); //查询数据 conn.query('select * from user', function(err, rows, fields) { if (err) throw err; //遍历返回的数据并设置到返回的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 }); }); // 关闭数据库链接 conn.end(); }); };
相比以前的代码只是引入了mysql,增长链接对象声明,而后在请求处理方法里查询数据,默认在数据库初始化了3条数据,以下截图,另外 为了简单起见我仍然使用的是RESTAdapter
适配器,这样处理也相对简单。 获取链接对象的代码应该不用过多解释了,就是填写你本地链接数据库的对应配置信息就好了。
记得修改适配器为RESTAdapter
。
重启项目。进入路由users
能够看到数据库的数据正确显示出来了。
对于CRUD操做都举一个例子,因为前面已经介绍过findAll
查询就不在此介绍CRUD中的R了。下面就对另外三个作一个例子:
更多有关数据的操做请看Ember.js 入门指南——新建、更新、删除记录。
为了方便演示再增长几个路由和模板。
ember g template users/index ember g route users/new ember g route users/edit
上述3个命令建立了三个users
的子路由和子模板。
因为项目使用的是Ember Data,增长数据也是很简单的,直接调用createRecord()
建立一个record
以后再调用save()
方法保存到服务器。
另外新增和更新的处理方式类似,就直接写在一个方法内。
// 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!"); } } } } });
新增和修改处理是类似的,根据id
是否为空判断是不是新增仍是更新。
{{! 新增、修改都用到的表单,提出为公共部分}} <div class="container"> <h1>{{title}}</h1> <div class="row bg-info" style="padding: 10px 20px 0 0;"> <p class="pull-right" style="margin-right: 20px;"> {{#link-to 'users' class="btn btn-primary"}}返回{{/link-to}} </p> </div> <!-- <form {{action 'add' on='submit'}}> --> <form> <div class="form-group"> <label for="exampleInputPassword1">username</label> {{input type="text" class="form-control" id="usernameId" name='username' placeholder="username" value=model.username}} </div> <div class="form-group"> <label for="exampleInputEmail1">Email address</label> {{input type="text" class="form-control" id="exampleInputEmail1" placeholder="Email" value=model.email}} </div> <button type="submit" class="btn btn-primary" {{action 'saveOrUpdate' model.id model}}>保存</button> </form> {{#if tipInfo}} <div class="alert alert-success alert-dismissible" role="alert"> <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button> {{tipInfo}} </div> {{/if}} </div>
// app/routes/users/edit.js import Ember from 'ember'; export default Ember.Route.extend({ // 根据id获取某个记录 model(params) { return this.store.findRecord('user', params.user_id); } });
点击“编辑”的时候须要根据被点击记录的id
查询数据详情,并返回到编辑页面。
{{! 增长数据的表单}} {{user-form title='新增user' store=store model=model}}
{{! 修改数据的表单}} {{user-form title='修改user' store=store model=model}}
提取新增和修改这两个模板的相同代码为一个组件,两个模板都调用组件。
与前端对应的要有相应的后端处理服务,增长2个路由监听,一个是监听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); // 打开数据库链接 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 { //没有数据返回一个空的 // 返回前端 res.status(200).send({ users: { id: '', username: '', email: '' } }); } }); console.log('sql: ' + query.sql); conn.release(); //释放链接,放回到链接池 }); }); // 处理请求 POST http://localhost:4200/users/id 根据id更新某个数据 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(); // 打开数据库链接 pool.getConnection(function(err, conn) { // 参数的次序要与SQL语句的参数次序一致 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; } //遍历返回的数据并设置到返回的json对象中,一般状况下只有一个数据,直接取第一个数据返回 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 { //没有数据返回一个空的 // // 返回前端 // res.status(200).send({ // users: { // id: '', // username: '', // email: '' // } // }); // } console.log('SQL: ' + query.sql); }); conn.release(); //释放链接,放回到链接池 }); });
为什么新增对应的是post
方法,更新对应的是put
方法,请看the rest adapter的详细介绍(主要是第一个表格的内容)。
点击右上角的新增按钮进入新增界面。
进入新增界面后输入相应信息(我就不作数据的格式校验了,有须要本身校验数据格式)。而后点击“保存”,保存成功会有提示信息。
点击右上角的“返回”回到主列表页面,查看新增的数据是否保存成功。
能够看到刚刚新增的数据已经显示在列表上,为了进一步验证数据已经保存成功,直接查看数据库。
能够看到数据库也已经成功保存了刚刚新增的数据。
修改的测试方式我就不啰嗦了,点击列表上的修改按钮进入修改页面,修改后保存既能够,请自行测试。
删除处理相比新增更加简单,直接发送一个delete
请求便可。
// 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 }); } } });
<!-- app/templates/index.hbs --> <h1>用户列表</h1> <div class="row bg-info" style="padding: 10px 20px 0 0;"> <p class="pull-right" style="margin-right: 20px;"> {{#link-to 'users.new' class="btn btn-primary"}}新增{{/link-to}} </p> </div> <table class="table table-striped table-hover"> <thead> <tr> <th> # </th> <th> 用户名 </th> <th> 邮箱 </th> <th> 操做 </th> </tr> </thead> <tbody> {{#each model as |user|}} <tr> <td> {{user.id}} </td> <td> {{user.username}} </td> <td> {{user.email}} </td> <td> {{#link-to 'users.edit' user.id}}修改{{/link-to}} | <span {{action 'del' user.id}} style="cursor: pointer; color: #337ab7;">删除</span> </td> </tr> {{/each}} </tbody> </table>
这段代码的与前面的代码基本一致,就是增长了删除。
在后端增长一个监听删除的路由。
// 处理请求 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); // 打开数据库链接 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(); //释放链接,放回到链接池 }); });
测试删除很简单,直接在列表上点击“删除”按钮便可删除一条记录。界面和数据库的截图我就不贴出来了,本身动手测试就知道了!!
数据能够正确删除,可是,删除以后控制台会报以下错误:
找了官网文档the rest adapter delete record按照官网的文档处理仍然报错!目前还没找到好的处理方法,不知道是哪里出了问题,若是读者知道请告诉我,谢谢。
到此CRUD操做也完成了,不足的就是在处理删除的时候仍是有点问题,目前还没找到以为办法!可是总的来讲对于CRUD的操做都是这么处理的,调用的方法也都是上述代码所使用的方法。
未完待续……还差分页没完成。
文章写到这里已经把我所想的内容介绍完毕了,不知道读者是否看明白了。其中主要理解的知识点是:
Ember Data和adapter、record、model的关系
如何自定义适配器
如何根据Ember前端请求编写后端处理
CRUD操做
分页处理(目前还没整合进来)
明白了上述几点,本文的目的也达到了!如何有疑问欢迎给我留言,也期待着读者能给我解答删除报错的问题!
若是有须要欢迎star或者fork学习。下面是源码地址:
https://github.com/ubuntuvim/emberData-adapter-database,欢迎follow我,一块儿学习交流!我在全球最大的同性交友网站等你哦!!