為您的Web項目構建一個簡單的JSON控制器

來源: IBM developerWorks  發布時間: 2011-10-09 16:19  閱讀: 3889 次  推薦: 1   原文鏈接   [收藏]  
摘要:無論您的項目使用的是哪種數據庫后端,JavaScript Object Notation (JSON) 控制器都能簡化您的開發工作。本文將帶領您建立一個能夠增強您的下一個開發項目的非常基礎的 JSON 控制器。

  您的下一個 PHP/MySQL 項目可能與您最近完成的十幾個項目類似:建立一個 MySQL 數據庫,創建包含 HTML 的 PHP 視圖,根據需要添加 JavaScript 代碼和 CSS 文件,連接到數據庫,從數據庫提取內容來填充視圖,等等。如果您熟悉 web 開發,您一定知道分隔功能代碼的好處。例如,您知道要避免直接在視圖中輸入原始 SQL 查詢,不會在從數據庫提取數據的函數或類中混淆 HTML 標記。

  但是,有時,您的項目可能擴展到您的正常 PHP/MySQL 舒適水平之外。例如,您可能不僅擁有需要來自一個數據庫的數據的常規 web 視圖,還擁有外部應用程序(比如 Facebook),甚至還擁有訪問相同數據的移動設備(比如智能手機)。

  您可能會發現自己身陷這樣一種情況:數據庫更改,或者要求您處理某種類型的 XML 存儲庫。在這些情況下,您對 MySQL 的盲目依賴可能會阻礙您完成項目的工作。

  可以考慮將一個 RESTful JSON 控制器放置到您的項目中,將它用作一個虛擬交通警察,負責發送請求并接收來自您的數據源的響應。本文將介紹 REST 和 JSON 的基礎知識,并展示一種建立控制器的方法。其結果是從一個數據源檢索數據的簡單方法,檢索的數據采用標準化的格式,可以使用 PHP 或 JavaScript 代碼輕松解析。

  什么是 REST?

  在一個典型的 REST 架構中,一個客戶機發送一個請求到服務器,服務器使用請求資源的一個表示來進行響應。資源可以是任何信息對象,比如數據庫或文檔,它的表示通常是一個格式化的文檔(通常是 XML 或 JSON),充當它的當前或被請求狀態的一個快照。

  REST 資源通常使用有意義的 URLs 標識,這些 URLs 接受不同的請求動詞 GET、POST、PUT 和 DELETE。這些動詞有點類似于許多開發人員都熟悉的 create-retrieve-update-delete (CRUD) 模型。

  例如,如果您想檢索數據,則使用 GET 請求;要創建數據,則使用 POST 請求;要更新數據,則使用 PUT 請求;最后,要刪除數據,則使用 DELETE 請求。

  另一個需要考慮的重要因素是響應。RESTful 服務通常在它的響應中提供兩個有意義的組件:響應主體本身和一個狀態碼。許多 REST 服務實際上允許用戶指定一個響應格式(比如 XML、CSV、序列化的 PHP 對象或純文本),方法有兩種:一是發送一個 ACCEPT 參數;二是指定一個文件擴展名(例如,/api/users.xml 或 /api/users.json)。其他 REST 服務器,比如您將在這里實現的服務器,擁有硬編碼的響應格式。這些格式同樣可以接受,只要它們已經有文檔記載。

  響應代碼往往是 HTTP 狀態碼。這種模式的優點是可以使用知名的現有狀態碼來標識錯誤或成功。狀態碼 201(CREATED)是一個成功 POST 請求的完美響應。錯誤碼 500 表明在您所處的這端(服務端)上發生了錯誤,但錯誤碼 400 表明客戶端上出現了失敗(BAD REQUEST)。如果服務器出現故障,將發送錯誤碼 503(SERVICE UNAVAILABLE)。

  研究一下下面這個示例:一個應用程序擁有的一個數據源包含一些用戶信息,名、姓、郵件地址、以及Twitter 帳戶。如果您正在設置一個典型的 PHP 應用程序,您需要創建一個 mysql_query() 包裝器來使用一個 SQL 查詢從數據庫提取一個清單。您還需要編寫一些 PHP 代碼,用于調用那個函數并循環結果集,以便在應用程序視圖中顯示數據。

  一個更簡單的方法是設置一個簡單的 REST 控制器,該控制器允許一個針對 /users/list 的、不帶任何參數的 GET 請求,然后調用適當的數據庫函數并返回一個 JSON 格式的清單。接下來,您的應用程序可以解碼那個 JSON 數據,以任何必要的方式循環該數據,以便顯示數據內容。

  另外,您可以通過測試檢查是否有任何參數被發送到 /users/list。例如,如果您發送一個 GET 請求到 /users/list/1,那么響應將只包含 ID 為 1 的用戶的細節。除 JSON 格式外,您甚至可以允許其他格式,比如 XML、CSV 和的 PHP 對象。

  一個 RESTful JSON 控制器對于您的開發工作的作用并非僅僅是在視圖和數據源之間放置一個額外的功能層。想想看,您的基本 PHP 視圖也許不是請求信息的惟一組件。例如,您可能會使用 jQuery 通過一個 Ajax 接口請求數據,或者,您的用戶可能會通過一部智能手機或一個 Facebook 應用程序請求數據。

  在這些情況下,一個接收請求并以一種容易理解(和預測)的格式提供響應的 RESTful 接口可能會極大地簡化您的開發工作。作為負責 PHP 視圖(或者甚至 iPhone 應用程序)的開發人員,您可以發送一些請求到一個 URL 并接收一組預期響應。在 JSON 控制器的另一面,應用程序可以被鉤掛(hook)到 MySQL、PostgreSQL、一個 XML 文件存儲庫、或者什么也不掛。

  什么是 JSON?

  JSON 是一種基于文本的輕量級數據交換格式,便于人類和計算機輕松理解和使用。在其出現之初,JSON 設計用于表示簡單數據結構。盡管它最初被視為用于傳輸特定的 JavaScript 友好數據的一種方法,但現在幾乎每臺計算機上都有針對它的解析器。在 PHP 中,一對原生 JSON 函數(json_encode 和 json_decode)將幫助您執行大量繁重的提升。只要將一組數據(或者甚至一個簡單字符串)發送到 json_encode,一個 JSON 對象將出現(如 清單 1 所示)。
  清單 1. 一個 PHP 數組 vs. 一個 JSON 對象

$data = array(
'firstname'=>'Tom',
'lastname'=>'Smith',
'age'=>40
);

print_r($data);

/* prints
Array(
[firstname] => Tom
[lastname] => Smith
[age] => 40
)

*/

echo json_encode($data);

/* prints
{ "firstname": "Tom",
"lastname": "Smith",
"age":40
}

*/

  注意,一個 SQL 查詢(其中鍵等于數據庫字段名、值等于數據)生成的典型 PHP 數組可以作為一個 JSON 對象輕松傳輸。到達時,數據可以簡單地使用 JavaScript 代碼(例如,來自一個 Ajax 上下文中)來進行 eval(),或者使用 PHP 中的 json_decode() 解碼,重新變為數據數組。

  JSON 支持除對象之外的各種數據類型:字符串、空值、數字(整數或實數)、布爾值和數組(包含在方括號中的逗號分隔的值序列)。因此,JSON 用戶在處理數據時體驗到了巨大的靈活性。

  本文將幫助您構建一個微型列表 JSON REST 控制器,您可以將其放置到您的模型和視圖功能之間。構建完成后,您可以隨意進行擴展以適應您的項目目標。

  構建一個基本 JSON 控制器

  想象一個提供事件信息的應用程序。所有事件信息都是公共的,因此身份驗證問題不是這里的主要考慮。另外,這個應用程序的目標是查詢今天發生的事件,并使用 JSON 將響應傳輸回請求發起者。現在,假定請求者是一個 PHP 視圖頁面。

  首先創建一個簡單的事件數據庫架構,類似于 清單 2 中的架構。
  清單 2. 數據庫架構(MySQL)

CREATE TABLE `events` (
`id`
INT NOT NULL AUTO_INCREMENT PRIMARYKEY ,
`title`
VARCHAR( 255 ) NOT NULL ,
`address`
VARCHAR( 255 ) NOT NULL ,
`start_time`
DATETIME NOT NULL ,
`description`
TEXT NOT NULL
);

  一旦數據庫表開始發揮作用,輸入幾條模擬數據記錄。確保至少有一天擁有多個為其安排的條目。接下來,創建一個典型 PHP 模型文件,它連接到這個數據庫并使用一個 SQL 查詢來識別事件。如果這是一個真實應用程序,您可能會分隔數據庫連接腳本和其余部分,并在您的查詢中進行各種數據驗證。您的代碼可能如清單 3 所示。
  清單 3. 一個簡單查詢

$SERVER = 'name';
$USER
= 'username';
$PASS
= 'pw';
$DATABASE
= 'dbname';

if (!($mylink = mysql_connect($SERVER, $USER, $PASS)))
{
echo
"Sorry, could not connect to DB. Contact your sysadmin for help!";
exit;
}
mysql_select_db( $DATABASE );

class Events{
function get_events($day){
$ret_array
= array();
$sql
="select id,title,address,start_time,description
from events where start_time like '$day%'
order by start_time asc";
$result = mysql_query($sql);

while($data = mysql_fetch_object($result)){
$obj[
'id'] = $data->id;
$obj[
'title'] = $data->title;
$obj[
'address'] = $data->address;
$obj[
'start_time'] = $data->start_time;
$obj[
'description'] = $data->description;

$ret_array[]
= $obj;
}

return $ret_array;
}
}

  當您使用您知道將檢索到一些事件的日期設置對這個函數的一個簡單調用時,您將得到如清單 4 所示的結果。
  清單 4. 運行查詢的結果

$EVENT = new Events;
$today
= '2010-06-17';
$events
= $EVENT->get_events($today);
print_r($events);

/* results in
Array
(
[0] => Array
(
[id] => 2
[title] => Event #2
[address] => 156 My Avenue, MyTown, USA 78727
[start_time] => 2010-06-17 11:30:00
[description] => Join us for lunch to hear
FABULOUS SPEAKER.
)

[1] => Array
(
[id] => 1
[title] => Event #1
[address] => 123 My Street, Anytown USA 78727
[start_time] => 2010-06-17 15:30:00
[description] => A great event! Hope to see you there!
)

)

*/

  如果您通過 json_encode() 運行相同的代碼,您將得到一個可移植的 JSON 對象(如 清單 5 所示)。
  清單 5. JSON 數據對象

[
{
"id":"2",
"title":"Event #2",
"address":"156 My Avenue, MyTown, USA 78727",
"start_time":"2010-06-17 11:30:00",
"description":"Join us for lunch to hear FABULOUS SPEAKER. "
},
{
"id":"1",
"title":"Event #1",
"address":"123 My Street, Anytown USA 78727",
"start_time":"2010-06-17 15:30:00",
"description":"A great event! Hope to see you there!"
}
]

  您的目標是構建這樣一個簡單的控制器:它知道應該運行哪個模型和函數,然后返回一個 JSON 對象作為響應,這個響應可用于事務的遠端。這個控制器非常簡單,看起來如清單 6 所示。將清單 6 中的所有代碼粘貼到一個名為 json.php 的文件中。
  清單 6. 一個簡單的控制器

class JSON{
var $response
= '';
function JSON($model,$function,$params){
$REQUEST
= new $model;
$data
= $REQUEST->$function($params);
$
this->response = json_encode($data);
}
}

  要使這段代碼生效,就需要用到您想調用的模型,實例化 JSON 類,然后傳入 3 個參數:模型的類名、要運行的函數、以及該函數的參數。這個類然后調用那個函數并獲取一個響應,該響應通過 json_encode() 運行。

  最后一步是創建包含對 JSON 數據的請求的文件。這個特殊的文件(您可以稱之為 listing.php)可以設置為接收 3 個 GET 變量(模型、函數和參數各一個),然后將這些變量傳遞給 JSON 類(如清單 7 所示)。
  清單 7. 請求代碼

//this is the code that contains the model
require 'events.php';

//this is the JSON controller
require 'json.php';

//pass in your three GET parameters
$MODEL = $_GET['model'];
$FUNCTION
= $_GET['function'];

//check to see if param is passed in
//if not, use today's date in this instance
if (isset($_GET['param'])){
$PARAM
= $_GET['param'];
}
else{
$PARAM
= date("Y-m-d");
}

//invoke
$JSON = new JSON($MODEL,$FUNCTION,$PARAM);

//access the response variable
echo $JSON->response;

  此時,您可以將這個文件加載到一個瀏覽器中,并獲取一個類似于清單 5 的 JSON 對象。您可以通過 json_decode() 將這個 JSON 對象發送回去,使用 JavaScript 代碼處理它,或者讓它保持原樣。

  整個這個流程的一個甚至更好的方法是創建一個更緊密模擬 RESTful 服務器的路徑結構。例如,您可以創建一個名為 events/today 的目錄結構,該結構包含一個名為 index.php 的文件。通過將您的瀏覽器指向 /events/today,無需傳入任何 GET 變量,您就可以基于清單 8 中的代碼取回一個 JSON feed。
  清單 8. /events/today/index.php 中的代碼

require '../../events.php';
require
'../../json.php';
$MODEL
="Events";
$FUNCTION
="get_events";
$PARAM
= date("Y-m-d");
//invoke
$JSON =new JSON($MODEL,$FUNCTION,$PARAM);
echo $JSON
->response;
//prints out
[
{
"id":"3",
"title":"Test Event 3",
"address":"111 Main Street, Austin TX 78727",
"start_time":"2010-06-10 15:15:00",
"description":"Testing 456."
}
]

  結束語

  使用這種方法,您可以為您的視圖和支持的應用程序簡化一些數據提取要求。開發人員無需記住底層數據庫的所有細節,相反,他們可以輕松命中 URLs 并接收他們尋找的響應來繼續他們的工作。

1
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()