美文网首页
Joomla框架实现REST风格 API的详细步骤

Joomla框架实现REST风格 API的详细步骤

作者: 老张带你飞 | 来源:发表于2020-02-08 20:45 被阅读0次

    1. 简介

    Joomla 是一款PHP语言开发的CMS系统,采用完全面向对象的MVC模式开发。支持多种开发方式。

    Joomla开发扩展的方式:

    1. Component : 组件模式,开发一套完整的组件应用的视图、数据库、逻辑;
    2. Module : 模块模式,能够在网页中显示的组件,例如登录模块等;
    3. Plugin : 插件模式,用于整个系统中,进行系统各个事件的处理,无界面;
    4. Template : 模版模式,用于自定义各种组件Component的外观;

    通常实现一个应用系统,会使用Component进行开发,利用Component可以开发前台展示端和后台管理端,因此本文使用Component作为实例说明。

    1.1 REST 风格

    REST风格是将HTTP网址、方法进行统一规范的方式,提供了一套通用的定义。例如:POST 方法用于创建资源,PUT方法用于更新资源,GET单纯获取资源;网址例如 /books 获取图书列表, /books/3.json 则是获取 id为 3 的图书信息。

    1.2 实例定义

    1. GET /api/books.json              返回图书列表,并且支持传递 page, size 参数;
    2. GET /api/books/{id}.json       返回特定图书的信息
    3. POST /api/books                    创建一个图书数据
    4. DELETE /api/books/{id}.json 删除一个图书数据
    

    2. 实现方式

    2.1 Joomla Component 开发简介

    Joomla的扩展开发需要一个关键的xml文件,这个文件定义了当前扩展的类型、基本信息、代码文件、配置信息和资源信息。通常都是在一个空目录中创建xml文件,并且增加对应的目录和代码,之后打包成zip/tar.gz 即可安装给Joomla。

    2.2 REST 风格的关键技术

    Joomla 中提供了一个 JRoute 类,这个类的方法会对传入的网址参数进行处理,映射成特定的 REST网址,可以进行网站的SEO优化。

    对于客户端等请求 REST网址的方式来说,需要反向将REST网址解析为实际的组件中的页面、处理器。

    实现上述方式都需要用到一个特定接口的实现: JComponentRouterInterface

    Component只要实现了这个接口,就可以实现REST风格网址的生成和解析。

    2.3 Joomla 网址请求规则

    Joomla中的所有的网址都是使用如下的格式来定义:

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

    其中 task 和 view不会并存。

    • option : 代表请求哪一个组件,我们的例子为 com_restdemo
    • view : 代表请求组件的哪一个 view 视图
    • layout : 代表请求 view 的哪一个显示模版
    • task : 代表调用 请求哪一个控制器的哪一个任务 通常是 controller.xxx 的方式
    • format : 代表要求返回哪种数据格式

    2.4 关键术语

    1. MVC : Joomla 使用MVC模式进行开发,每一个部分用于处理不同的需求
    2. Task : Joomla 组件通过网址访问,网址中使用 task 参数可以直接调用Controller 的方法,可以不需要网页显示
    3. 文件名称特性:PHP文件中可以包含 format 类型,这样可以让Joomla自动查找对应的文件,例如 view.html.php 代表输出 HTML格式的代码;view.json.php 则代表输出 json 格式的内容。

    2.5 初始工程代码段

    1. 初始化步骤
      创建一个空的目录,例如 D:\restdemo 目录(Windows),或者 ~/restdemo 目录(Linux),在restdemo目录中创建任意名称的 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目录中创建 com_restdemo 目录,并且在这个目录中,继续创建restdemo.php文件,controller.php 文件,controllers 子目录,models 子目录,和views 子目录。

    组件被执行的时候,会自动查找和加载 restdemo.php 文件,通过这个文件加载组件的处理器,这个处理器是通过 controller.php 定义的,也是自动加载的,处理器会根据请求的 view, format, layout, task 等参数,来自动的查找 controllers, views 子目录中的类,进行处理。

    1. restdemo.php 主入口
      主入口会创建主Controller,执行相关操作,也就是 controller.php 会被自动加载。对应的代码如下:
    <?php
    // Joomla 代码必须在第一行加入这句话
    defined('_JEXEC') or die;
    
    // 创建 Controller对象,名称前缀为 RestDemo的对象
    //     Joomla 代码会自动将所有类的 名称转换为小写再加载文件
    //     本代码会自动加载 controller.php 文件,并且创建对象
    $controller = JControllerLegacy::getInstance('RestDemo');
    
    // 处理器处理网址参数 task 并进行逻辑处理,
    // 如果没有设置,默认处理 task=display
    $controller->execute(JFactory::getApplication()->input->get('task'));
    $controller->redirect();
    
    1. 主控制器 controller.php
      主控制器名称是 RestDemoController ,其中 RestDemo 就是 restdemo.php中指定的前缀。所有的 代码都是以 RestDemo 开头。主控制器默认的任务为 display,这个任务会自动加载view进行显示,默认名称为 restdemo 的view,可以设置 default_view 来修改。
    <?php
    
    defined('_JEXEC') or die;
    
    /**
     * 主控制器,主控制器默认会处理 display 任务
     * display 会自动加载 views/restdemo 目录的 view
     */
    class RestDemoController extends JControllerLegacy
    {
        /**
         * 设置 display 任务时 默认显示为 views/index/view.html.php,
         * 如果不设置,则会要求加载 views/restdemo/view.html.php
         */
        protected $default_view = 'index';
    }
    
    1. 制作index视图
      在 views 目录中,创建一个新的目录,名称为 "index", 并且在 index中创建view.html.php 的文件。
      最终的路径为 com_restdemo/views/index/view.html.php
    <?php
    defined('_JEXEC') or die;
    
    // RestDemo 为前缀,View 代表是View类型,Index 就是对应的 "index" 页面
    class RestDemoViewIndex extends JViewLegacy
    {
        public function display($tpl = null)
        {
            return parent::display($tpl);
        }
    }
    

    默认的代码 display 会在当前 view.html.php 文件下查找 tmpl/default.php 的文件,作为实际的输出内容。完整路径为
    com_restdemo/views/index/tmpl/default.php

    <?php
    
    defined('_JEXEC') or die;
    
    echo 'Hello World by vhly.';
    
    1. 打包安装

    默认的Component 已经完成,先进行安装测试,打包文件:

    • restdemo.xml
    • com_restdemo 目录

    将这两个部分压缩成一个压缩包,可以采用 zip 方式,打包之后,在Joomla后台管理“扩展安装”菜单进行安装即可。

    1. 测试页面

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

    这个地址会默认查找 com_restdemo 组件的前台页面,会找到 restdemo.php 并且最终显示 index的内容。

    默认测试页面

    2.6 增加 REST 地址映射

    由于Component组件包含前台代码和后台管理代码,相当于两套代码,通过 xml文件进行描述,本文没有编写后台管理代码,因此只处理前台代码的REST映射。

    只要在 com_restdemo 文件夹增加 router.php 文件,并且实现代码,就可以增加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>
                    <!-- 此处增加一个文件!!! -->
            <filename>router.php</filename>
            <folder>controllers</folder>
            <folder>models</folder>
            <folder>views</folder>
        </files>
    
        <administration>
    
        </administration>
    
    </extension>
    
    1. 增加 com_restdemo/router.php 文件

    创建 RestDemoRouter 类,并且实现 JComponentRouteInterface
    需要实现三个方法,方法并不是必须要有实际的代码,根据需求来实现。

    • preprocess($query) 方法:在生成地址之前处理请求参数
    • build(&$query) 方法:自己实现生成 rest/seo 风格的地址
    • parse(&$segments) 方法:解析REST风格的网址 !!
    <?php
    
    defined('_JEXEC') or die;
    
    class RestDemoRouter implements JComponentRouterInterface
    {
    
        /**
         * 预处理 query 请求,这个是网址中的 各个请求参数
         */
        public function preprocess($query)
        {
            return $query;
        }
    
        /**
         * 这个方法生成 rest 风格的网址,或者是 SEO友好的网址
         * 将类似 index.php?option=com_restdemo&view=index 转化
         * 成类似这样的网址 index.php/com_restdemo/index.html
         */
        public function build(&$query)
        {
            // TODO: Implement build() method.
        }
    
        /**
         * 此方法将 REST 风格网址解析成实际的请求地址
         * 这个方法是重要的
         */
        public function parse(&$segments)
        {
            // TODO: Implement parse() method.
        }
    }
    

    3. 实现REST风格API

    3.1 测试生成 /api/books.json API

    这个API请求需要注意几个关键特征:

    • 请求返回的格式必须是 json,也就是 application/json 类型
    • 请求的方法是 GET

    设计思路:

    1. 请求的内容是 JSON,不需要使用页面,直接使用Controller即可;
    2. 使用Controller,需要定义 task 来对应请求;
    3. Controller 必须是支持JSON的,不能够是默认HTML的,需要单独创建;
    4. JSON 响应使用 JResponseJSON 来封装;
    5. Router 中只要实现 parse 即可,其余两个方法不是必须的;

    实现步骤:

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

    每当请求为 api/books.json 那么调用实际的地址变成:
    index.php?option=com_restdemo&task=api.books&format=json

    /**
         * 此方法将 REST 风格网址解析成实际的请求地址
         * 这个方法是重要的
         */
        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]) {
                            // 开始设置地址请求参数
                            // 1. 设置 task = api.books
                            $query['task'] = 'api.books';
                            // 2. 设置 format = 'json'
                            $query['format'] = 'json';
                        }
                    }
                }
            }
            return $query;
        }
    
    1. 创建 API Controller,路径为 com_restdemo/controllers/api.json.php

    名称 api.json.php 只有到 format=json时,回调用这个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数据:

    JSON数据响应
    1. 获取实际的REST地址

    实现 router.php 中的 build 方法,看一下最终生成的地址是什么样子的。
    规则如下:

    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
                            // 转换为 api/books.json
                            $segments[] = 'api';
                            $segments[] = 'books.json';
    
                            // 清除参数,注意保留业务参数
                            unset($query['task']);
                            unset($query['format']);
                        }
                    }
                }
            }
            return $segments;
        }
    
    1. 测试REST地址
      Joomla中不需要直接使用 Router的代码,而是通过 JRoute::_() 方法来调用。
      参数就是请求地址,会自动传递给 build 方法。

    在 com_restdemo/views/index/tmpl/default.php 中调用输出,进行测试:

    <?php
    
    defined('_JEXEC') or die;
    
    $booksUrl = JRoute::_('index.php?option=com_restdemo&task=api.books&format=json');
    
    echo 'Books URL: '.$booksUrl;
    
    
    

    输出结果:

    最终输出地址

    最终输出地址为:
    /index.php/component/restdemo/api/books.json

    1. 生成短地址

    如果对于地址有更严格的限制,要求生成 http://IP/api/books.json 的方式,那么
    需要将 com_restdemo 的内容设置为网站默认首页,就会隐藏掉 index.php 和 component 信息。

    1. 在 com_restdemo/views/index/tmpl/ 目录,创建 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>
    
    

    重新打包安装。

    进入后台菜单项管理,创建新的菜单项

    新建菜单项

    选择菜单项类型为组件页面:

    选择组件作为页面

    设置为默认首页

    即可生成: index.php/api/books.json 地址,直接访问 http://IP/api/books.json 同样可以返回数据

    4. 附加链接

    相关文章

      网友评论

          本文标题:Joomla框架实现REST风格 API的详细步骤

          本文链接:https://www.haomeiwen.com/subject/hriixhtx.html