Ext JS 6學習文檔-第4章-數據包
數據包
本章探索 Ext JS 中處理數據可用的工具以及服務器和客戶端之間的通信。在本章結束時將寫一個調用 RESTful 服務的例子。下面是本章的內容:
- 模型
- Schema
- Stores
- 代理
- 過濾和排序
- 做一個基於 RESTful 的小項目
Model(模型)
一個模型包含字段,字段類型,校驗,關聯和代理。它是通過擴展 Ext.data.Model 類來定義的。
其中類型,校驗,關聯和代理都是可選的。 當一個字段沒有指定類型時,將使用默認類型 ‘auto’。 通常 代理都是設置在 store 中,但是 model 里也可以設置代理。
Field(字段)
Ext.data.field.Field 用於添加模型的屬性。 這個屬性字段的類型可以是預定義的或自定義類型。下列是可用的預定義類型:
- auto
- boolean
- date
- int
- number
- string
數據轉換
默認當你為一個字段指定類型后,這個數據將在保存到該字段之前進行轉換。轉換的過程由內置的 convert 方法處理。auto 字段類型不具備 convert 方法,所以 auto 類型的字段不會發生轉換。
其他所有的字段類型都有 convert 方法。如果你想避免其他字段轉換來提高性能,你可以通過指定各自的轉換配置為 null 。如下列 Employee 模型所示。
驗證器/校驗器
數據模型支持數據的校驗。下列是支持的驗證器:
- presence: 確保值是存在於一個字段
- format: 能夠用一個正則表達式來進行驗證
- length: 支持最大和最小長度的驗證
- exclusion 和 inclusion: 你可以通過給出一組值來確保字段的值存在或不存在於這組值中。
下列代碼示例展示一個 Employee 模型,在模型的字段上使用驗證器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [
{ name: 'id', type: 'int', convert: null },
{ name: 'firstName', type: 'string' },
{ name: 'lastName', type: 'string' },
{ name: 'fulltime', type: 'boolean', defaultValue: true, convert: null },
{ name: 'gender', type: 'string' },
{ name: 'phoneNumber', type: 'string'},],
validators: {
firstName: [{
type: 'presence'
},{
type: 'length',
min: 2
}],
lastName:[{
type: 'presence'
},{
type: 'length',
min: 2
}],
phoneNumber: {
type: 'format',
matcher: '/^[(+{1})|(00{1})]+([0-9]){7,10}$/'
},gender: {
type: 'inclusion',
list: ['Male', 'Female']
}
}
});
|
創建一個模型的實例,使用 Ext.create ,如以下代碼所示:
1
2
3
4
5
6
7
8
|
var newEmployee = Ext.create('Employee', {
id : 1,
firstName : 'Shiva',
lastName : 'Kumar',
fulltime : true,
gender: 'Male',
phoneNumber: '123-456-7890'
});
|
創建好的模型對象有 get 和 set 方法用來讀取和設置字段值:
1
|
var lastName = newEmployee.get('lastName'); newEmployee.set('gender','Female');
|
關系
定義實體之間的關系,使用下列關系類型之一:
One-to-one(一對一)
下列代碼代表一對一關系:
1
2
3
4
5
6
7
8
|
Ext.define('Address', {
extend: 'Ext.data.Model',
fields: [
'address',
'city',
'state',
'zipcode']
});
|
1
2
3
4
5
6
7
|
Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [{
name: 'addressId',
reference: 'Address'
}]
});
|
One-to-many(一對多)
下列代碼代表一對多關系:
1
2
3
4
5
6
7
|
Ext.define('Department', {
extend: 'Ext.data.Model',
fields: [{
name: 'employeeId',
reference: 'Employee'
}]
});
|
1
2
3
4
5
6
7
|
Ext.define('Division', {
extend: 'Ext.data.Model',
fields: [{
name: 'departmentId',
reference: 'Department'
}]
});
|
Many-to-many(多對多)
下列代碼代表多對多關系:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [{
name: 'empId',
type: 'int',
convert: null
},{
name: 'firstName',
type: 'string'
},{
name: 'lastName',
type: 'string'
}],
manyToMany: 'Project'
});
|
1
2
3
4
5
6
7
|
Ext.define('Project', {
extend: 'Ext.data.Model',
fields: [
'name'
],
manyToMany: 'Employee'
});
|
自定義字段類型
你也可以通過簡單的擴展 Ext.data.field.Field 類來創建自定義字段類型。如以下代碼所示:
1
2
3
4
5
6
7
8
9
|
Ext.define('App.field.Email', {
extend: 'Ext.data.field.Field',
alias: 'data.field.email',
validators: {
type: 'format',
matcher: /^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
message: 'Wrong Email Format'
}
});
|
Store
一個 store 代表一個 模型的實例 的集合並用於代理獲取數據。store 還定義了集合操作,例如 排序,過濾等等。它是通過擴展 Ext.data.Store 定義的。
通常,當定義一個 store ,你需要為 store 指定一個 代理。這是一個配置屬性,它告訴 store 如何讀取和寫入數據。在本章的后面我們將會看到更多詳細的不同種類的代理。
下列代碼是一個 store 的例子,它使用 RESTful API 請求加載為 JSON 格式數據:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var myStore = Ext.create('Ext.data.Store', {
model: 'Employee',
storeId: 'mystore',
proxy: {
type: 'rest',
url: '/employee',
reader: {
type: 'json',
rootProperty: 'data'
}
},
autoLoad: true,
autoSync: true
});
|
這里 storeId 是 store 的唯一標示符。這個 store 有一個方法 load ,用於通過代理配置加載數據。如果你設置 autoLoad 為 true ,那么當 store 創建后將會自動調用 load 方法。如果設置 autoLoad 為 false ,那么你可以手動的調用 load 方法加載數據。
同樣的,你可以設置 autoSync 為 true ,當你對 store 的記錄進行修改新增和刪除時將會自動發生同步。
在前面的例子中,當在 store 中執行修改,新增或刪除時,它將調用 REST service API 。如果你設置這個屬性為 false ,那么你可以調用 sync 方法執行同步操作。
調用 sync 方法將觸發一個批量操作。所以如果你添加和刪除了多條記錄,那么調用 sync方法這個過程中將觸發多次服務器調用。這是一個 sync 調用的例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
store.sync({
callback: function (batch, options) {
//Do something
},
success: function (batch, options) {
//Do something
},
failure: function (batch, options) {
//Do something
},
scope: this
});
|
這里,當所有 sync 操作全部完成並且沒有任何例外和失敗時調用 success 方法。如果有一個或多個操作在 sync 過程中失敗,將調用 failure 方法。callback 方法則會在同步操作完成后,不論成功失敗都會被調用。
如果 failure 被調用,你可以檢查 batch 異常數組來看到什么操作失敗,為什么。這里 options 是 sync 方法中傳遞的原始參數。
這個 sync 方法調用時也可以添加一個屬性 params ,它可以用於在同步的時候傳遞任意你想附加的參數。
內聯數據 store
如果你不想綁定 store 到服務器或外部存儲,例如瀏覽器本地存儲,但還想使用一些特殊的的靜態數據,那么可以直接硬編碼內聯數據到 store ,如以下代碼所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Ext.create('Ext.data.Store', {
model: 'Employee',
data: [{
firstName: 'Shiva',
lastName: 'Kumar',
gender: 'Male',
fulltime: true,
phoneNumber: '123-456-7890'
},{
firstName: 'Vishwa',
lastName: 'Anand',
gender: 'Male',
fulltime: true,
phoneNumber: '123-456-7890'
}]
});
|
過濾和排序
store 支持本地或遠程的過濾和排序。下面是本地排序的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
var myStore = Ext.create('Ext.data.Store', {
model: 'Employee',
sorters: [{
property: 'firstName',
direction: 'ASC'
}, {
property: 'fulltime',
direction: 'DESC'
}],
filters: [{
property: 'firstName',
value: /an/
}]
});
|
使用遠程排序和遠程過濾,需要設置 remoteSort 和 remoteFilter 屬性為 true 。如果你設置為 true ,那么在服務器端你必須要執行過濾和排序並為客戶端返回過濾或排序后的數據。
訪問 store
你也許需要在應用的其他地方訪問這個 store 有很多方法可以用。
使用 StoreManager 訪問 store
使用 store 管理器的 lokkup 方法,你能夠在程序的任何地方來訪問 store。為此我們需要使用 storeId ,注意,當 store 通過一個控制器實例化的時設置 storeId,storeId 將會被覆蓋,這是一個例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Ext.create('Ext.data.Store', {
model: 'Employee',
storeId: 'mystore',
proxy: {
type: 'rest',
url: '/employee',
reader: {
type: 'json',
rootProperty: 'data'
}
}
});
|
假設我們已經創建了 store 如上所示。現在你可以通過傳遞 storeId 到 store 管理器的 StoreManager.lookup 方法訪問這個 store,如以下代碼所示:
1
|
Ext.data.StoreManager.lookup('myStore');
|
你也可以使用 Ext.getStore 方法。Ext.getStore 是 Ext.data.StoreManager.lookup 的快捷方法。
使用 Ext.app.ViewModel 訪問 store
你可以通過 Ext.app.ViewModel 的 getStore 方法 訪問 store 。當你是在 ViewController 中,最好使用這種方式,下面是代碼示例:
1
|
var myStore = this.getViewModel().getStore('myStore')
|
這個 getStore 方法也定義在 view 中,你也可以用它訪問 store。
Store 事件
store 提供了很多可監聽的事件。store 的一些常用事件:
- add: 當一條記錄添加到 store 后調用
- beforeload: 在加載數據之前調用
- beforesync: 在進行同步操作之前調用
- datachanged: 當 store中的記錄產生新增或刪除時觸發調用
- load: 當 store 讀取一個遠程數據源后觸發調用
- remove: 從 store 移除一條記錄觸發調用
- update: 當 store 中的一條記錄被更新觸發調用
給出的一個 store 事件監聽的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Ext.create('Ext.data.Store', {
model: 'Employee ',
storeId: 'mystore',
proxy: {
type: 'rest',
url: '/employee',
reader: {
type: 'json',
rootProperty: 'data'
}
},
listeners: {
load: function (store, records, options) {
//Do something
}
}
});
|
如果你想在你的控制器中監聽 store 事件,你可以這樣做:
1
2
3
|
init: function() {
this.getViewModel().getStore('myStore').on('load', this.onStoreLoad, this);
}
|
在 ViewModel 中定義 store
你可以分別定義 store 和 ViewModel 或者定義到一起。通常可取的定義 store 在 ViewModel 自身。一個例子如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
Ext.define('MyApp.view.employee.EmployeeModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.employee',
stores: {
employee: {
fields: [{
name: 'id',
type: 'string'
},{
name: 'firstname',
type: 'string'
},{
name: 'lastname',
type: 'string'
}],
autoLoad: false,
sorters: [{
property: 'firstname',
direction: 'ASC'
}],
proxy: {
type: 'rest',
url: 'employee',
reader: {
type: 'json',
},
writer: {
type: 'json'
}
}
}
}
});
|
代理
所有的 stores 和 models 使用 proxy 來加載和保存數據。在代理中使用這個配置你可以指定如何讀取和寫入數據。你也可以指定調用 URL 讀取數據;你可以告訴讀取器這些數據的格式,不論是 JSON 還是 XML ,等等。
有兩種類型的代理:客戶端代理和服務器代理。
客戶端代理
客戶端代理是用於處理客戶端本身數據的加載和保存。這氛圍三種客戶端代理:內存,本地存儲,和會話存儲。
內存代理
內存代理是用於內存中的局部變量數據。下列代碼展示了一個內存代理的例子。在這里這個數據的值沒有硬編碼。只要是合適的格式,可以是任何變量的數據:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
var data = {
data: [{
firstName: 'Shiva',
lastName: 'Kumar',
gender: 'Male',
fulltime: true,
phoneNumber: '123-456-7890'
},{
firstName: 'Vishwa',
lastName: 'Anand',
gender: 'Male',
fulltime: true,
phoneNumber: '123-456-7890'
}]
};
var myStore = Ext.create('Ext.data.Store', {
model: 'Employee',
data : data,
proxy: {
type: 'memory',
reader: {
type: 'json',
rootProperty: 'Employee'
}
}
});
|
本地存儲代理
這個是用於訪問瀏覽器本地存儲。它是一個鍵值對存儲添加在 html5 ,所以需要瀏覽器支持:
1
2
3
4
5
6
7
8
|
var myStore = Ext.create('Ext.data.Store', {
model: 'Benefits',
autoLoad: true,
proxy: {
type: 'localstorage',
id: 'benefits'
}
});
|
會話存儲代理
這個是用於訪問瀏覽器會話存儲。這也是一個 html5 特性,因此需要比較現代的瀏覽器才能支持。這些數據是當 session 超時后會被銷毀:
1
2
3
4
5
6
7
8
|
var myStore = Ext.create('Ext.data.Store', {
model: 'Benefits',
autoLoad: true,
proxy: {
type: 'localstorage',
id : 'benefits'
}
});
|
服務器端代理
服務器端代理是向服務器通信來讀取或保存數據。有四種代理:
- Ajax: 用於異步請求數據
- Direct: 使用 Direct 與服務器通信
- JSONP (JSON with padding): 這很有用,當你需要發送跨域請求時。而 ajax 只能請求相同的域。
- REST: 這會向服務器發送一個 ajax 請求,使用 RESTful 的風格,例如 GET,POST,PUT,和 DELETE。
在本章我們已經看到過一個 REST 代理的例子。讓我們瞧一瞧 JSONP 的例子:
1
2
3
4
5
6
7
8
|
var myStore = Ext.create('Ext.data.Store', {
model: 'Products',
proxy: {
type: 'jsonp',
url : 'http://domain.com/products',
callbackKey: 'productsCallback'
}
});
|
備忘錄(RESTful 的示例項目)
現在,讓我們運用本章和前面章節所學內容,創建一個 備忘錄 應用。這里我們將使用 store 的 REST 代理來連接 REST 服務。
我們來創建一個簡單的 RESTful 服務,我們將使用 Go 語言,也稱為 Golang 。它由 Google 開發,是靜態語言,語法松散。
你不必學習 Go 語言,這個項目主要集中在 Ext JS 的教學。你可以用任意的你熟悉的語言替換 Go 語言開發的 RESTful 服務代碼。
這是我們將要創建的應用的設計:
讓我們瞧一瞧這個項目的一些重要文件。完整的代碼在這里 https://github.com/ananddayalan/extjs-by-example-todo。
下面截圖展示了這個程序的目錄結構:
首先,讓我們先來創建 store ,我們已經在本章學習過了。這里我將 store 寫在 ViewModel 中。
下列 ViewModel中有三個字段:id ,desc(描述) ,done(顯示待辦是否完成),代理類型為 rest 並設置 URL 地址為 tasks 。因為是 REST 代理,它將會根據不同的操作訪問相應的 HTTP 服務。
例如,當你刪除一條記錄,這個服務請求 URL 將是 <base URL>/task/{id} 。如果你的應用部署在 localhost 端口為 9001 ,那么請求 URL 就是http://localhost:9001/tasks/23333 ,並且 HTTP verb 是 DELETE ,你可以理解為提交的 HTTP 動作類型。這里 23333 是記錄的ID。當你添加一條記錄,URL 就是 http://localhost:9001/tasks ,這時 HTTP verb 就是 POST,同時要添加的記錄也會以 JSON 形式發送給服務器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
Ext.define('ToDo.view.toDoList.ToDoListModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.todoList',
stores: {
todos: {
fields: [ {
name: 'id',
type: 'string'
},{
name: 'desc',
type: 'string'
}],
autoLoad: true,
sorters: [{
property: 'done',
direction: 'ASC'
}],
proxy: {
type: 'rest',
url: 'tasks',
reader: {
type: 'json',
},
writer: {
type: 'json'
}
}
}
}
});
|
現在我們來創建視圖,我們將創建一個 view 作為 備忘錄列表,一個文本框用於鍵入新的待辦,和一個添加按鈕。
這個備忘錄列表的 UI 是基於 store 中的記錄,動態的創建的,並且每當一個記錄添加或移除,這個 view 都會相應的更新。Ext JS grid 組件可以實現我們的目的,但是你還沒有學習過這個組件,所以這里我們不使用它來創建,而通過其他方式,你還將學習到如何處理自定義 UI。
動態創建 待辦列表 UI,我把代碼寫在 ViewController 里。在這個 view 中,我添加了 文本框 和 按鈕:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
Ext.define('ToDo.view.toDoList.ToDoList', {
extend: 'Ext.panel.Panel',
/* Marks these are required classes to be to loaded before loading this view */
requires: [
'ToDo.view.toDoList.ToDoListController',
'ToDo.view.toDoList.ToDoListModel'
],
xtype: 'app-todoList',
controller: 'todoList',
/* View model of the view. */
viewModel: {
type: 'todoList'
},
items: [{
xype: 'container',
items: [{
xtype: 'container',
layout: 'hbox',
cls: 'task-entry-panel',
defaults: {
flex: 1
},
items: [{
reference: 'newToDo',
xtype: 'textfield',
emptyText: 'Enter a new todo here'
},{
xtype: 'button',
name: 'addNewToDo',
cls: 'btn-orange',
text: 'Add',
maxWidth: 50,
handler: 'onAddToDo'
}]
}]
}]
});
|
上面的 view 代碼里,我指定了兩個 cls 屬性分別是 btn-orange 和 task-entry-panel 。這是 CSS 類,用於添加一些 CSS 樣式。在上面的 UI 截圖中,你可以看到 Add 按鈕並不是我們所用的主題(crisp)的默認顏色。因為我指定了 CSS 類來自定義這個按鈕了。
現在我們可以創建 ViewController 。我們將通過在初始化函數中讀取 store 中的記錄來創建 待辦列表 的UI 。這里,一旦應用加載,我們將調用 store 的 load 方法。這將使得 rest 服務調用,從服務器獲取記錄,並遍歷結果,每一條記錄我們都會創建一行在 UI 中。
提供刪除功能,我會在每一條記錄上添加一個刪除圖標。下列代碼用於綁定這個圖標的點擊事件。待辦記錄 UI 是動態生成的,所以我們需要事件委派,如以下代碼所示:
1
2
3
|
Ext.getBody().on('click', function (event, target) {
me.onDelete(event, target);
} , null, {delegate: '.fa-times' });
|
如果 UI 不是動態添加的,正常的綁定點擊事件,如以下代碼:
1
2
3
|
Ext.select('fa-times').on('click', function (event, target) {
me.onDelete(event, target);
});
|
以下是視圖待辦列表(ToDoList) 的視圖控制器(ViewController)的代碼。 onAddToDo 方法是添加按鈕的點擊事件處理,方法里通過lookupReference 方法傳遞引用名稱設置到 ToDoList 視圖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
Ext.define('ToDo.view.toDoList.ToDoListController', {
extend: 'Ext.app.ViewController',
alias: 'controller.todoList',
views: ['ToDo.view.toDoList.ToDoList'],
init: function () {
var me = this;
//Here we're calling the load method of the store and passing an anonymous method for the callback. So, the load will call the server to get the data first and calls the anonymous method. The anonymous method then, add the data to the view.
this.getViewModel().data.todos.load(function (records) {
Ext.each(records, function (record) {
//Add a container for each record
me.addToDoToView(record);
});
});
Ext.getBody().on('click', function (event, target) {
me.onDelete(event, target);
}, null, {
delegate: '.fa-times'
});
},
onAddToDo: function () {
var store = this.getViewModel().data.todos;
//newToDo 就是文本框的 引用
var desc = this.lookupReference('newToDo').value.trim();
if (desc != '') {
store.add({
desc: desc
});
store.sync({
success: function (batch, options) {
this.lookupReference('newToDo').setValue('');
this.addToDoToView(options.operations.create[0]);
},
scope: this
});
}
},
addToDoToView: function (record) {
this.view.add([{
xtype: 'container',
layout: 'hbox',
cls: 'row',
items: [{
xtype: 'checkbox',
boxLabel: record.get('desc'),
checked: record.get('done'),
flex: 1
},{
html: '<a class="hidden" href="#"><i taskId="' + record.get('id') + '" class="fa fa-times"></i></a>',
}]
}]);
},
onDelete: function (event, target) {
var store = this.getViewModel().data.todos;
var targetCmp = Ext.get(target);
var id = targetCmp.getAttribute('taskId');
store.remove(store.getById(id));
store.sync({
success: function () {
this.view.remove(targetCmp.up('.row').id)
},
scope: this
});
}
});
|
最后,讓我們來創建 REST 服務。Go 語言可以安裝在 mac OS,Windows,linux 等等。這里下載 https://golang.org.
Go 語言安裝完成之后,你需要設置 GOROOT 環境變量為 Go 語言的安裝目錄。linux 應該添加下列命令到 $HOME/.profile:
1
|
export GOROOT=/usr/local/go export PATH=$PATH:$GOROOT/bin
|
針對本項目,我將使用一個名為 Gorilla 的路由模塊,安裝這個模塊使用以下命令:
1
|
go get github.com/gorilla/mux
|
以下是 REST 服務的代碼。
- 這段代碼不會存數據到數據庫里,所有的數據都是在內存中,當你關閉程序,數據將被銷毀。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
package main
import ( "fmt"
"encoding/json"
"net/http" "strconv"
"github.com/gorilla/mux"
)
type Task struct {
Id string `json:"id"`
Desc string `json:"desc"`
Done bool `json:"done"`
}
var tasks map[string] *Task
func GetToDo(rw http.ResponseWriter, req * http.Request) {
vars := mux.Vars(req)
task := tasks[vars["id"]]
js, err := json.Marshal(task)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprint(rw, string(js))
}
func UpdateToDo(rw http.ResponseWriter, req * http.Request) {
vars := mux.Vars(req)
task:= tasks[vars["id"]]
dec:= json.NewDecoder(req.Body)
err:= dec.Decode( & task)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
task.Id = vars["id"]
retjs, err:= json.Marshal(task)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprint(rw, string(retjs))
}
func DeleteToDo(rw http.ResponseWriter, req * http.Request) {
vars := mux.Vars(req)
delete(tasks, vars["id"])
fmt.Fprint(rw, "{status : 'success'}")
}
func AddToDo(rw http.ResponseWriter, req * http.Request) {
task:= new(Task)
dec:= json.NewDecoder(req.Body)
err:= dec.Decode( & task)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
tasks[task.Id] = task
retjs, err:= json.Marshal(task)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprint(rw, string(retjs))
}
func GetToDos(rw http.ResponseWriter, req * http.Request) {
v := make([]*Task, 0, len(tasks))
for _, value := range tasks {
v = append(v, value)
}
js, err:= json.Marshal(v)
if err != nil {
http.Error(rw, err.Error(), http.StatusInternalServerError)
return
}
fmt.Fprint(rw, string(js))
}
func main() {
var port = 9001
router:= mux.NewRouter()
tasks = make(map[string] *Task)
router.HandleFunc("/tasks", GetToDos).Methods("GET")
router.HandleFunc("/tasks", AddToDo).Methods("POST")
router.HandleFunc("/tasks/{id}", GetToDo).Methods("GET")
router.HandleFunc("/tasks/{id}", UpdateToDo).Methods("PUT")
router.HandleFunc("/tasks/{id}", DeleteToDo).Methods("DELETE")
router.PathPrefix("/").Handler(http.FileServer(http.Dir("../")))
fmt.Println("Listening on port", port)
http.ListenAndServe("localhost:" + strconv.Itoa(port), router)
}
|
使用下列命令運行服務:
1
|
go run ToDo.go
|
如果沒有報錯,應該顯示類似於以下代碼:
1
|
Listening on port 9001
|
現在你可以訪問 localhost:9001 查看應用了:
完整的代碼在這里 https://github.com/ananddayalan/extjs-byexample-todo.
總結
在本章中,你學習了如何創建 model,store,代理和如何處理數據。同時也看到如何使用 Go 語言創建一個簡單的 REST 服務。