《Ext JS 6.2实战》节选——Ext JS的跨平台特性

时间:2021-05-24 01:12:24


很多希望学习或需要学习Ext JS的开发人员,都会习惯性地问以下问题:Ext JS与自己熟悉的开发语言结合得如何?开发起来方便吗?对于初次接触Ext JS的人来说,问这个问题不奇怪,毕竟Ext JS与他们之前所熟悉的开发模式有很大不同。如果对Ext JS了解深入并掌握开发方法后,就会发现,Ext JS其实是一个很好的跨语言平台的开发框架。对于使用混合平台或需要进行平台迁移的项目来说,是非常好的选择。在本章,在介绍Ext JS的跨平台特性之外,还会通过把简单的CMS系统迁移到Java平台的演示来验证Ext JS的跨平台特性。

13.1 Ext JS跨平台特性简介

这里所说的Ext JS跨平台特性主要是指Ext JS的开发语言平台无关性,也就是说,无论你熟悉的后台开发语言是C#、Java还是PHP,甚至是C++或C,都没有关系,只要能根据固定的格式返回数据,使用Ext JS开发的应用程序就能正常运行。进一步来说,Ext JS的开发工作,可以由前端工程师使用模拟数据独立完成,而无须知道后台是如何运作的。
为什么Ext JS会有这样的跨平台特性呢?这主要是缘于Ext JS通过存储等组件实现了数据与界面的分离,以及通过Ext.Ajax实现了数据交互接口的标准化。
使用Ext JS,最大的感受就是数据与界面是分离的,数据的操作基本都可以围绕存储进行,而存储与后台之间的数据交互则使用标准化的格式进行。对于不一定与存储打交道的表单等数据的交互,也是以标准化格式进行的。这些因素综合起来,就彻底把后台与前台界面分离开来了。这样做的最终结果,就把Ext JS打造成了可以实现跨平台的框架。
这样说有点抽象,还是做个演示,使大家对Ext JS的跨平台特性有个清晰的认识。

13.2 在JAVA平台使用SimpleCMS

13.2.1 概述

要验证Ext JS是否能实现跨平台的迁移,只需要把简单的CMS系统的应用程序直接复制到Java平台上,看是否需要脚本代码就清楚了。如果不需要,就说明Ext JS是可以实现跨平台迁移的,如果需要修改,则说明不可以。

13.2.2 搭建开发环境

本书使用的Eclipse版本是4.7.0版。打开Eclipse,并创建一个名为SimpleCMS-JAVA的动态网页项目。项目创建后,先别急于把应用程序添加到项目里,否则会因脚本验证造成假死。
要取消脚本验证,选择主菜单Window→Preferences打开Preferences对话框。在对话框左侧找到Validation,然后在右边的列表中找到Client-side JavaScript,把Manual和Build两列处于选中状态的复选框取消选择。最后单击Apply and Close完成更改。

13.2.3 添加应用程序

把验证取消后,就可以把应用程序复制到项目的WebContent\Sencha文件夹里了。

13.2.4 创建首页文件

在项目的WebContent文件夹下新建一个index.jsp文件,然后把WebContent\Sencha文件夹下的index.html文件里的内容替换掉index.jsp中的HTML代码。
代码复制完成后,在加载bootstrap.js文件的SCRIPT标记上添加以下ROOTPATH的定义代码:

<script>
var ROOTPATH = 'http://localhost:8080/SimpleCMS-JAVA';
</script>

ROOTPATH添加完后,为bootstrap.js添加路径Sencha,注意大小写。

13.2.5 修改app.json文件

打开app.json文件,将indexHtmlPath中的index.html修改为index.jsp。然后生成一次应用程序。

13.2.6 修改SimpleCMS.util.Url

打开SimpleCMS.util.Url的类文件,把getResource方法中的sencha修改为Sencha。Tomcat默认配置下路径区分大小写,比较麻烦。

13.2.7 添加Json-lib

对于一般的Ext JS项目来说,返回JSON格式是必不可少的,所以必须为项目添加JSON库,这里将使用Json-lib这个库,可以到http://json-lib.sourceforge.net/中下载。
要使用这个库,还需要以下类库支持:

  • jakarta commons-lang 2.5
  • jakarta commons-beanutils 1.8.0
  • jakarta commons-collections 3.2.1
  • jakarta commons-logging 1.1.1
  • ezmorph 1.0.6

对于以上几个公共库,可以访问http://commons.apache.org/来下载。对于ezmorph库则可以访问http://ezmorph.sourceforge.net/来下载。
13.2.8 辅助类ExtJs
在6.2.3小节,创建了辅助类ExtJS,并添加了一个WriterJObject方法来统一输出接口,而这正是实现数据标准化交互的关键之一,在Java项目中,这当然也是少不了的。
下面,在项目中新建一个Java类,并加入静态方法WriterJObject,代码如下:

package Helper;

import net.sf.json.*;

public class ExtJs {
    public static JSONObject WriteObject(
            boolean success,
            JSONObject errors,
            int total,
            String msg,
            JSONObject dataJsonObject,
            JSONArray dataJsonArray
            ) {
        JSONObject jo = new JSONObject();
        jo.put("success", success);
        if(errors != null){
            jo.put("errors", errors);
        }
        if(total>0){
            jo.put("total",total);
        }
        if(msg != null){
            jo.put("msg", msg);         
        }
        if(dataJsonObject != null){
            jo.put("data", dataJsonObject);
        }
        if(dataJsonArray != null){
            jo.put("data", dataJsonArray);
        }       
        return jo;
        }
}

从代码可以看到,把类放在了Helper包里。由于不清楚Java如何定义可变参数,也不知道能否将data参数定义为object类型,然后自行转换为JSONObject或JSONArray进行处理,所以把全部参数都定义为固定参数,且定义了dataJsonObject和dataJsonArray这两个参数来处理JSONObject和JSONArray类型的data属性。
与C#版的还有个不同的地方是total参数,由于不能为null,且该参数只有在值大于0的时候才有意义,所以,将它设置为大于0的时候才将total属性添加到返回对象中。
有了这个方法,一切就变得简单了。

13.2.9 创建Servlet:GetUserInfo

现在,一切都准备好了,可以进行测试。在项目中新建一个名为UserInfo的Servlet,包的名称为Account,访问地址为account/userinfo。文件创建后,先添加getMenu方法用来返回菜单,代码如下:

protected JSONArray getMenu() {
    JSONObject menu1 = new JSONObject();
    menu1.put("text", "文章管理");
    menu1.put("iconCls", "x-fa fa-file-text-o");
    menu1.put("rowCls", "nav-tree-badge");
    menu1.put("viewType", "articleView");
    menu1.put("routeId", "articleView");
    menu1.put("leaf", "true");

    JSONObject menu2 = new JSONObject();
    menu2.put("text", "媒体管理");
    menu2.put("iconCls", "x-fa fa-file-image-o");
    menu2.put("rowCls", "nav-tree-badge");
    menu2.put("viewType", "mediaView");
    menu2.put("routeId", "mediaView");
    menu2.put("leaf", "true");

    JSONObject menu3 = new JSONObject();
    menu3.put("text", "用户管理");
    menu3.put("iconCls", "x-fa fa-user");
    menu3.put("rowCls", "nav-tree-badge");
    menu3.put("viewType", "userView");
    menu2.put("routeId", "userView");
    menu3.put("leaf", "true");


    JSONArray jArray = new JSONArray();
    jArray.add(menu1);
    jArray.add(menu2);
    jArray.add(menu3);
    return jArray;
}
如果有数据库,可以从数据库中获取菜单。菜单写好以后,在doGet方法中添加以下代码来返回用户信息:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
    JSONObject userInfo = new JSONObject();
    userInfo.put("UserName", "admin");
    userInfo.put("Roles", "['系统管理员']");

    JSONObject jo = new JSONObject();
    jo.put("UserInfo", userInfo);
    jo.put("Menu", getMenu());
    JSONObject result = ExtJs.WriteObject(true, null, 0, null, jo, null);
    response.setContentType("text/javascript; charset=utf-8");
    response.getWriter().write(result.toString());
}

在doGet方法中,只是参照C#代码中登录后的返回结果组合了一些用户信息返回客户端。
现在可以运行项目了。项目运行后,会发现页面已经顺利地进入到管理系统,显示与在C#平台上看到是一模一样的。这说明,迁移已经成功了。余下的工作基本就是根据所需的数据定义SerLet进行数据交互了。至于客户端的代码,基本不需要做任何修改,是不是很方便?

13.3 在PHP平台使用SimpleCMS

13.3.1 搭建开发环境

本书将使用Yii框架 的基本模版来实现PHP版本的SimpleCMS。在地址https://github.com/yiisoft/yii2/releases/download/2.0.12/yii-basic-app-2.0.12.tgz下载完框架包后,先使用管理员权限运行解压缩软件,然后再打开框架包,将包里的basic目录解压出来。需要使用管理器权限是因为有些文件不用管理员权限解压不出来,比较麻烦。
文件解压后,把basic里的文件全部复制到项目的文件夹,笔者的项目文件夹为D:\Workspace\PHP\SimpleCMS-PHP。

13.3.2 在XAMPP设置访问路径

这个Yii2框架总体来说还算不错,但最让人讨厌的就是它的访问路径设置。最简单的设置就是给一个虚拟域名给它,不要搞什么虚拟目录之类的。如果使用高级模版,那更烦人。
在XAMPP的控制面板(Control Panle)中,在Apache模块的Config的下拉列表中选择Apache(httpd-xampp.conf),打开Apache的xampp配置文件。然后在配置文件添加以下代码替换XAMPP原来的根目录设置:

DocumentRoot "/Workspace/PHP/SimpleCMS-PHP/web/"
    <Directory "/Workspace/PHP/SimpleCMS-PHP/web/">
        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule . index.php

        Options Indexes FollowSymLinks Includes ExecCGI
        AllowOverride All
        Require all granted
    </Directory>

配置文件保存后,重新启动一下Apache。
现在访问网站,会出现Invalid Configuration的错误,因为还没配置好Yii框架。

13.3.3 配置Yii框架

打开项目的config文件夹下的web.php文件,找到cookieValidationKey配置,将它的值修改为simplecms,然后找到urlManager配置,将它的代码修改为以下代码:

'urlManager' => [
    'enablePrettyUrl' => true,
    'showScriptName' => false,
    'baseUrl' => '/',
    'rules' => [
    ],
],

现在再打开网站,就可以顺利看到示例页面了。

13.3.4 添加应用程序

如果使用的是Eclipse作为PHP的开发工具,请参展13.2.2节的内容,先将脚本验证取消,再将应用程序复制到项目的web\Sencha文件夹下。
应用程序复制后,将web\Sencha文件夹下index.html文件复制到web文件夹下作为伪装的首页文件。

13.3.5 修改首页文件

打开views\site文件夹下的index.php文件。先将title变量删除,然后使用index.html内的代码覆盖index.php内的HTML代码。
代码复制后,在加载bootstrap.js的SCRIPT标记上,添加以下ROOTPATH的定义代码:

<script type="text/javascript">
var ROOTPATH = 'http://localhost:8081';
</script>

为了避免和IIS的冲突,笔者将XAMPP的访问端口修改为了8081,具体使用什么端口,请大家根据自己的XAMPP设置咨询修改。
添加ROOTPATH后,将bootstrap.js的路径修改为sencha。
由于Yii框架的页面默认是使用布局的,但这个布局对于我们来说完全是多余,因而,我们必须修改控制器,让它不渲染布局。打开controllers文件夹下的SiteController.php文件,找到actionIndex方法,将渲染首页使用的render方法修改为不使用布局的renderAjax方法。

13.3.6 辅助类ExtJs

由于PHP输出JOSN数据比较方便,有没有6.2.3小节所讲述的辅助类ExtJs其实问题不大,不过,辅助类的其他方法还是需要的。
要创建辅助类ExtJs,可以在项目中新建一个名为common的文件夹,然后在文件夹内新建一个名为ExtJs的类。类创建后,在类内添加一个名为WriteObject的静态方法,代码如下:

public static function WriteObject($success, $errors =null, $total= null, $msg=null, $data=null)
{
    $obj= array ('success'=>$success);
    if(!empty($errors)) $obj['errors'] = $errors;
    if(!empty($msg)) $obj['msg'] = $msg;
    if(!empty($total)) $obj['total'] = $total;
    if(!empty($data)) $obj['data'] = $data;
    return json_encode($obj,JSON_UNESCAPED_UNICODE);
}

在类中,要保证命名空间为app\common。

13.3.7 创建AccountController控制器

在controllers文件夹下新建一个名为AccountController的类,类的命名空间为app\controllers。类创建后,参考SiteController,先把use开头的代码复制过来,然后在类声明上添加extends关键字,让AccountController派生于yii\web\Controller。
接下来添加getMenu方法,代码如下:

private function getMenu(){
    return array(
        0=>array( 'text'=>'文章管理', 'iconCls'=>'x-fa fa-file-text-o', 'rowCls'=>'nav-tree-badge', 'viewType'=>'articleView', 'routeId'=>'articleView', 'leaf'=>'true'),
        1=>array( 'text'=>'媒体管理', 'iconCls'=>'x-fa fa-file-image-o', 'rowCls'=>'nav-tree-badge', 'viewType'=>'mediaView', 'routeId'=>'mediaView', 'leaf'=>'true'),
        2=>array( 'text'=>'用户管理', 'iconCls'=>'x-fa fa-user', 'rowCls'=>'nav-tree-badge', 'viewType'=>'userView', 'routeId'=>'userView', 'leaf'=>'true')
    );
}

代码就是一些数组的简单组合,写起来比Java那个方便多了。
最后是添加actionUserinfo方法,代码如下:

public function actionUserinfo()
{
    return ExtJs::WriteObject(true,null,null,null,array(
        'UserInfo'=> array('UserName'=>'admin', 'Roles'=>'系统管理员'),
        'Menu'=> $this->getMenu()
    ));
}

在Yii框架中,控制器中的操作都是以action开头的方法,因而方法名必须是actionUserinfo。在actionUserinfo方法,只是参照C#代码中登录后的返回结果组合了一些用户信息返回客户端。
现在浏览器打开项目,会发现页面已经顺利地进入到管理系统,显示与在C#平台上看到是一模一样的。这说明,迁移已经成功了。余下的工作基本就是根据所需的数据定义控制器进行数据交互了。至于客户端的代码,基本不需要做任何修改,是不是很方便?

13.4 小结

在本章,主要讲述并演示了Ext JS的跨平台性。很多Ext JS的初学者,都喜欢找与自己所熟悉的开发语言的Ext JS示例来学习,而且总是会问一些使用某种语言如何返回数据和获取数据的问题。这说明这位初学者在学习思路上已经走偏了,而结果可能是越学越难,最终不得不放弃。
要实现Ext JS的跨平台性,一个很关键的地方还是要看开发人员的开发方式,如果用老思维来开发Ext JS的应用程序,在页面中混合好多HTML代码和Ext JS脚本,那么也是实现不了Ext JS的跨平台性的。而这样也就无法完全发挥Ext JS的优点。
本章的目的就是做个范例,让大家来学习如何充分利用Ext JS的特性来进行开发,以便开发出健康的、可维护性高和代码可阅读性高的应用程序。