Joomla框架實現(xiàn)REST風(fēng)格 API的詳細步驟

1. 簡介

Joomla 是一款PHP語言開發(fā)的CMS系統(tǒng)迹淌,采用完全面向?qū)ο蟮腗VC模式開發(fā)沟堡。支持多種開發(fā)方式油吭。

Joomla開發(fā)擴展的方式:

  1. Component : 組件模式雕憔,開發(fā)一套完整的組件應(yīng)用的視圖逾雄、數(shù)據(jù)庫含懊、邏輯结借;
  2. Module : 模塊模式筐摘,能夠在網(wǎng)頁中顯示的組件,例如登錄模塊等船老;
  3. Plugin : 插件模式咖熟,用于整個系統(tǒng)中,進行系統(tǒng)各個事件的處理柳畔,無界面馍管;
  4. Template : 模版模式,用于自定義各種組件Component的外觀薪韩;

通常實現(xiàn)一個應(yīng)用系統(tǒng)确沸,會使用Component進行開發(fā),利用Component可以開發(fā)前臺展示端和后臺管理端俘陷,因此本文使用Component作為實例說明罗捎。

1.1 REST 風(fēng)格

REST風(fēng)格是將HTTP網(wǎng)址、方法進行統(tǒng)一規(guī)范的方式拉盾,提供了一套通用的定義桨菜。例如:POST 方法用于創(chuàng)建資源,PUT方法用于更新資源,GET單純獲取資源倒得;網(wǎng)址例如 /books 獲取圖書列表, /books/3.json 則是獲取 id為 3 的圖書信息泻红。

1.2 實例定義

1. GET /api/books.json              返回圖書列表,并且支持傳遞 page, size 參數(shù);
2. GET /api/books/{id}.json       返回特定圖書的信息
3. POST /api/books                    創(chuàng)建一個圖書數(shù)據(jù)
4. DELETE /api/books/{id}.json 刪除一個圖書數(shù)據(jù)

2. 實現(xiàn)方式

2.1 Joomla Component 開發(fā)簡介

Joomla的擴展開發(fā)需要一個關(guān)鍵的xml文件霞掺,這個文件定義了當(dāng)前擴展的類型谊路、基本信息、代碼文件根悼、配置信息和資源信息凶异。通常都是在一個空目錄中創(chuàng)建xml文件,并且增加對應(yīng)的目錄和代碼挤巡,之后打包成zip/tar.gz 即可安裝給Joomla剩彬。

2.2 REST 風(fēng)格的關(guān)鍵技術(shù)

Joomla 中提供了一個 JRoute 類,這個類的方法會對傳入的網(wǎng)址參數(shù)進行處理矿卑,映射成特定的 REST網(wǎng)址喉恋,可以進行網(wǎng)站的SEO優(yōu)化。

對于客戶端等請求 REST網(wǎng)址的方式來說母廷,需要反向?qū)EST網(wǎng)址解析為實際的組件中的頁面轻黑、處理器。

實現(xiàn)上述方式都需要用到一個特定接口的實現(xiàn): JComponentRouterInterface

Component只要實現(xiàn)了這個接口琴昆,就可以實現(xiàn)REST風(fēng)格網(wǎng)址的生成和解析氓鄙。

2.3 Joomla 網(wǎng)址請求規(guī)則

Joomla中的所有的網(wǎng)址都是使用如下的格式來定義:

index.php?option=com_xxx&view=vvv&layout=lll&task=ttt&format=fff

其中 task 和 view不會并存。

  • option : 代表請求哪一個組件业舍,我們的例子為 com_restdemo
  • view : 代表請求組件的哪一個 view 視圖
  • layout : 代表請求 view 的哪一個顯示模版
  • task : 代表調(diào)用 請求哪一個控制器的哪一個任務(wù) 通常是 controller.xxx 的方式
  • format : 代表要求返回哪種數(shù)據(jù)格式

2.4 關(guān)鍵術(shù)語

  1. MVC : Joomla 使用MVC模式進行開發(fā)抖拦,每一個部分用于處理不同的需求
  2. Task : Joomla 組件通過網(wǎng)址訪問,網(wǎng)址中使用 task 參數(shù)可以直接調(diào)用Controller 的方法舷暮,可以不需要網(wǎng)頁顯示
  3. 文件名稱特性:PHP文件中可以包含 format 類型态罪,這樣可以讓Joomla自動查找對應(yīng)的文件,例如 view.html.php 代表輸出 HTML格式的代碼下面;view.json.php 則代表輸出 json 格式的內(nèi)容复颈。

2.5 初始工程代碼段

  1. 初始化步驟
    創(chuàng)建一個空的目錄,例如 D:\restdemo 目錄(Windows)沥割,或者 ~/restdemo 目錄(Linux)耗啦,在restdemo目錄中創(chuàng)建任意名稱的 xml 文件,例如 restdemo.xml机杜。
<?xml version="1.0" encoding="utf-8" ?>
<extension type="component" version="3.8" method="upgrade">
    <name>COM_RESTDEMO</name>
    <creationDate>2020/2/8</creationDate>
    <author>vhly</author>
    <authorEmail>your@email.com</authorEmail>
    <authorUrl>http://your.url.com</authorUrl>
    <copyright>A copyright</copyright>
    <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
    <version>1.0</version>
    <description>COM_RESTDEMO_XML_DESCRIPTION</description>

    <!-- Front-end files -->
    <files folder="com_restdemo">
        <filename>restdemo.php</filename>
        <filename>controller.php</filename>
        <folder>controllers</folder>
        <folder>models</folder>
        <folder>views</folder>
    </files>

    <administration>
            <!-- 暫時不加后臺處理 -->
    </administration>

</extension>

在restdemo目錄中創(chuàng)建 com_restdemo 目錄芹彬,并且在這個目錄中,繼續(xù)創(chuàng)建restdemo.php文件叉庐,controller.php 文件舒帮,controllers 子目錄,models 子目錄,和views 子目錄玩郊。

組件被執(zhí)行的時候肢执,會自動查找和加載 restdemo.php 文件,通過這個文件加載組件的處理器译红,這個處理器是通過 controller.php 定義的预茄,也是自動加載的,處理器會根據(jù)請求的 view, format, layout, task 等參數(shù)侦厚,來自動的查找 controllers, views 子目錄中的類耻陕,進行處理。

  1. restdemo.php 主入口
    主入口會創(chuàng)建主Controller刨沦,執(zhí)行相關(guān)操作诗宣,也就是 controller.php 會被自動加載。對應(yīng)的代碼如下:
<?php
// Joomla 代碼必須在第一行加入這句話
defined('_JEXEC') or die;

// 創(chuàng)建 Controller對象想诅,名稱前綴為 RestDemo的對象
//     Joomla 代碼會自動將所有類的 名稱轉(zhuǎn)換為小寫再加載文件
//     本代碼會自動加載 controller.php 文件召庞,并且創(chuàng)建對象
$controller = JControllerLegacy::getInstance('RestDemo');

// 處理器處理網(wǎng)址參數(shù) task 并進行邏輯處理,
// 如果沒有設(shè)置,默認處理 task=display
$controller->execute(JFactory::getApplication()->input->get('task'));
$controller->redirect();
  1. 主控制器 controller.php
    主控制器名稱是 RestDemoController 来破,其中 RestDemo 就是 restdemo.php中指定的前綴篮灼。所有的 代碼都是以 RestDemo 開頭。主控制器默認的任務(wù)為 display徘禁,這個任務(wù)會自動加載view進行顯示诅诱,默認名稱為 restdemo 的view,可以設(shè)置 default_view 來修改送朱。
<?php

defined('_JEXEC') or die;

/**
 * 主控制器娘荡,主控制器默認會處理 display 任務(wù)
 * display 會自動加載 views/restdemo 目錄的 view
 */
class RestDemoController extends JControllerLegacy
{
    /**
     * 設(shè)置 display 任務(wù)時 默認顯示為 views/index/view.html.php,
     * 如果不設(shè)置骤菠,則會要求加載 views/restdemo/view.html.php
     */
    protected $default_view = 'index';
}
  1. 制作index視圖
    在 views 目錄中,創(chuàng)建一個新的目錄疤孕,名稱為 "index", 并且在 index中創(chuàng)建view.html.php 的文件商乎。
    最終的路徑為 com_restdemo/views/index/view.html.php
<?php
defined('_JEXEC') or die;

// RestDemo 為前綴祭阀,View 代表是View類型鹉戚,Index 就是對應(yīng)的 "index" 頁面
class RestDemoViewIndex extends JViewLegacy
{
    public function display($tpl = null)
    {
        return parent::display($tpl);
    }
}

默認的代碼 display 會在當(dāng)前 view.html.php 文件下查找 tmpl/default.php 的文件,作為實際的輸出內(nèi)容专控。完整路徑為
com_restdemo/views/index/tmpl/default.php

<?php

defined('_JEXEC') or die;

echo 'Hello World by vhly.';
  1. 打包安裝

默認的Component 已經(jīng)完成抹凳,先進行安裝測試,打包文件:

  • restdemo.xml
  • com_restdemo 目錄

將這兩個部分壓縮成一個壓縮包伦腐,可以采用 zip 方式赢底,打包之后,在Joomla后臺管理“擴展安裝”菜單進行安裝即可。

  1. 測試頁面

http://xxx.xxx.xxx.xxx/index.php?option=com_restdemo

這個地址會默認查找 com_restdemo 組件的前臺頁面幸冻,會找到 restdemo.php 并且最終顯示 index的內(nèi)容粹庞。

默認測試頁面

2.6 增加 REST 地址映射

由于Component組件包含前臺代碼和后臺管理代碼,相當(dāng)于兩套代碼洽损,通過 xml文件進行描述庞溜,本文沒有編寫后臺管理代碼,因此只處理前臺代碼的REST映射碑定。

只要在 com_restdemo 文件夾增加 router.php 文件流码,并且實現(xiàn)代碼,就可以增加REST映射了延刘。

具體修改如下:

  1. 修改 restdemo.xml 文件
<?xml version="1.0" encoding="utf-8" ?>
<extension type="component" version="3.8" method="upgrade">
    <name>COM_RESTDEMO</name>
    <creationDate>2020/2/8</creationDate>
    <author>vhly</author>
    <authorEmail>your@email.com</authorEmail>
    <authorUrl>http://your.url.com</authorUrl>
    <copyright>A copyright</copyright>
    <license>GNU General Public License version 2 or later; see LICENSE.txt</license>
    <version>1.0</version>
    <description>COM_RESTDEMO_XML_DESCRIPTION</description>

    <!-- Front-end files -->
    <files folder="com_restdemo">
        <filename>restdemo.php</filename>
        <filename>controller.php</filename>
                <!-- 此處增加一個文件B浴!访娶! -->
        <filename>router.php</filename>
        <folder>controllers</folder>
        <folder>models</folder>
        <folder>views</folder>
    </files>

    <administration>

    </administration>

</extension>
  1. 增加 com_restdemo/router.php 文件

創(chuàng)建 RestDemoRouter 類商虐,并且實現(xiàn) JComponentRouteInterface
需要實現(xiàn)三個方法,方法并不是必須要有實際的代碼崖疤,根據(jù)需求來實現(xiàn)秘车。

  • preprocess($query) 方法:在生成地址之前處理請求參數(shù)
  • build(&$query) 方法:自己實現(xiàn)生成 rest/seo 風(fēng)格的地址
  • parse(&$segments) 方法:解析REST風(fēng)格的網(wǎng)址 !劫哼!
<?php

defined('_JEXEC') or die;

class RestDemoRouter implements JComponentRouterInterface
{

    /**
     * 預(yù)處理 query 請求叮趴,這個是網(wǎng)址中的 各個請求參數(shù)
     */
    public function preprocess($query)
    {
        return $query;
    }

    /**
     * 這個方法生成 rest 風(fēng)格的網(wǎng)址,或者是 SEO友好的網(wǎng)址
     * 將類似 index.php?option=com_restdemo&view=index 轉(zhuǎn)化
     * 成類似這樣的網(wǎng)址 index.php/com_restdemo/index.html
     */
    public function build(&$query)
    {
        // TODO: Implement build() method.
    }

    /**
     * 此方法將 REST 風(fēng)格網(wǎng)址解析成實際的請求地址
     * 這個方法是重要的
     */
    public function parse(&$segments)
    {
        // TODO: Implement parse() method.
    }
}

3. 實現(xiàn)REST風(fēng)格API

3.1 測試生成 /api/books.json API

這個API請求需要注意幾個關(guān)鍵特征:

  • 請求返回的格式必須是 json权烧,也就是 application/json 類型
  • 請求的方法是 GET

設(shè)計思路:

  1. 請求的內(nèi)容是 JSON眯亦,不需要使用頁面,直接使用Controller即可般码;
  2. 使用Controller妻率,需要定義 task 來對應(yīng)請求;
  3. Controller 必須是支持JSON的板祝,不能夠是默認HTML的宫静,需要單獨創(chuàng)建;
  4. JSON 響應(yīng)使用 JResponseJSON 來封裝券时;
  5. Router 中只要實現(xiàn) parse 即可孤里,其余兩個方法不是必須的;

實現(xiàn)步驟:

  1. 在 router.php 的 parse 方法橘洞,增加 api/books.json 的支持捌袜,映射到controller

每當(dāng)請求為 api/books.json 那么調(diào)用實際的地址變成:
index.php?option=com_restdemo&task=api.books&format=json

/**
     * 此方法將 REST 風(fēng)格網(wǎng)址解析成實際的請求地址
     * 這個方法是重要的
     */
    public function parse(&$segments)
    {
        $query = array(); // 返回查詢字段,拼接成 key1=value1&key2=value2
        $slen = count($segments);
        if ($slen > 0) {
            // api 開頭
            if ('api' === $segments[0]) {
                if ($slen > 1) {
                    // 請求為 api/books.json
                    if ('books.json' === $segments[1]) {
                        // 開始設(shè)置地址請求參數(shù)
                        // 1. 設(shè)置 task = api.books
                        $query['task'] = 'api.books';
                        // 2. 設(shè)置 format = 'json'
                        $query['format'] = 'json';
                    }
                }
            }
        }
        return $query;
    }
  1. 創(chuàng)建 API Controller炸枣,路徑為 com_restdemo/controllers/api.json.php

名稱 api.json.php 只有到 format=json時虏等,回調(diào)用這個PHP文件

<?php

defined('_JEXEC') or die;

class RestDemoControllerApi extends JControllerLegacy
{
    /**
     * task = api.books 會自動映射到這個方法
     */
    public function books(){
        // 所有其余的請求都會通過input來獲取
        $input = JFactory::getApplication()->input;

        $books = array();

        $book = new stdClass();
        $book->title = 'Book 001';
        $books[] = $book;

        $book = new stdClass();
        $book->title = 'Book 002';
        $books[] = $book;

        echo new JResponseJson($books, 'Books', false);
    }
}
  1. 打包測試

請求地址:http://XXX.XXX.XXX.XXX/index.php?option=com_restdemo&task=api.books&format=json

返回JSON數(shù)據(jù):

JSON數(shù)據(jù)響應(yīng)
  1. 獲取實際的REST地址

實現(xiàn) router.php 中的 build 方法弄唧,看一下最終生成的地址是什么樣子的。
規(guī)則如下:

  1. build 方法檢查 task 是否是 api.books
  2. 檢查 format 是否是 json
  3. 通過檢查博其,拼接地址
    public function build(&$query)
    {
        $segments = array(); // 地址拼接
        if (isset($query['task'])) {
            $task = $query['task'];
            if (isset($query['format'])) {
                $format = $query['format'];

                if ('json' === $format) {
                    if ('api.books' === $task) {
                        // 將 task=api.books&format=json
                        // 轉(zhuǎn)換為 api/books.json
                        $segments[] = 'api';
                        $segments[] = 'books.json';

                        // 清除參數(shù)套才,注意保留業(yè)務(wù)參數(shù)
                        unset($query['task']);
                        unset($query['format']);
                    }
                }
            }
        }
        return $segments;
    }
  1. 測試REST地址
    Joomla中不需要直接使用 Router的代碼,而是通過 JRoute::_() 方法來調(diào)用慕淡。
    參數(shù)就是請求地址背伴,會自動傳遞給 build 方法。

在 com_restdemo/views/index/tmpl/default.php 中調(diào)用輸出峰髓,進行測試:

<?php

defined('_JEXEC') or die;

$booksUrl = JRoute::_('index.php?option=com_restdemo&task=api.books&format=json');

echo 'Books URL: '.$booksUrl;


輸出結(jié)果:

最終輸出地址

最終輸出地址為:
/index.php/component/restdemo/api/books.json

  1. 生成短地址

如果對于地址有更嚴格的限制傻寂,要求生成 http://IP/api/books.json 的方式,那么
需要將 com_restdemo 的內(nèi)容設(shè)置為網(wǎng)站默認首頁携兵,就會隱藏掉 index.php 和 component 信息疾掰。

1. 在 com_restdemo/views/index/tmpl/ 目錄,創(chuàng)建 default.xml 文件定義菜單鏈接

<?xml version="1.0" encoding="utf-8"?>
<metadata>
    <layout title="COM_RESTDEMO_RESTDEMO">
        <message>
            <![CDATA[COM_RESTDEMO_RESTDEMO_DESC_MENU]]>
        </message>
    </layout>
</metadata>

重新打包安裝徐紧。

進入后臺菜單項管理静檬,創(chuàng)建新的菜單項

新建菜單項

選擇菜單項類型為組件頁面:

選擇組件作為頁面

設(shè)置為默認首頁

即可生成: index.php/api/books.json 地址,直接訪問 http://IP/api/books.json 同樣可以返回數(shù)據(jù)

4. 附加鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末并级,一起剝皮案震驚了整個濱河市拂檩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘲碧,老刑警劉巖稻励,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異愈涩,居然都是意外死亡望抽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門履婉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煤篙,“玉大人,你說我怎么就攤上這事毁腿〖危” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵狸棍,是天一觀的道長身害。 經(jīng)常有香客問我味悄,道長草戈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任侍瑟,我火速辦了婚禮唐片,結(jié)果婚禮上丙猬,老公的妹妹穿的比我還像新娘。我一直安慰自己费韭,他們只是感情好茧球,可當(dāng)我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著星持,像睡著了一般抢埋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上督暂,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天揪垄,我揣著相機與錄音,去河邊找鬼逻翁。 笑死饥努,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的八回。 我是一名探鬼主播酷愧,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼缠诅!你這毒婦竟也來了溶浴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤滴铅,失蹤者是張志新(化名)和其女友劉穎戳葵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汉匙,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡拱烁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了噩翠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片戏自。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伤锚,靈堂內(nèi)的尸體忽然破棺而出擅笔,到底是詐尸還是另有隱情,我是刑警寧澤屯援,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布猛们,位于F島的核電站,受9級特大地震影響狞洋,放射性物質(zhì)發(fā)生泄漏弯淘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一吉懊、第九天 我趴在偏房一處隱蔽的房頂上張望庐橙。 院中可真熱鬧假勿,春花似錦、人聲如沸态鳖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浆竭。三九已至浸须,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邦泄,已是汗流浹背羽戒。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虎韵,地道東北人易稠。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像包蓝,于是被迫代替她去往敵國和親驶社。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容