[saiku] 访问saiku首页的时候前后台处理流程

 

这篇文章讲述:
项目启动后,首次访问SAIKU的登录页,前后台分别做了什么处理

 

(1) 访问的到底是什么页面?

浏览器输入:localhost:8080 啪一回车
根据web访问的尿性,访问的是 index.jsp 或者 index.html

先看看 index.jsp ,没什么内容

<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Pentaho BI Platform</title>
    <META HTTP-EQUIV="refresh" CONTENT="0;URL=./serverdocs">
  </head>
  <body>
  </body>
</html>

<meta http-equiv="refresh" content="0; url=">
表示:经过一段时间转到另外某个页面
这里0表示没有延时,直接跳转到后面的URL;把0改成1,则延时1秒后跳转。 
这就是为什么有的人访问localhost:8080会跳转到localhost:8080/saiku/serverdocs的原因


再看看 index.html 

代码太多,你需要知道一点:配置中引入了所有需要的JS和CSS(除了一些需要动态加载的JS和CSS)
因为不管访问什么请求,地址栏都是localhost:8080没变过,得知所有的接口调用都是ajax异步请求
因此,所有需要的JS和CSS必然都是在index.html中引入包含了

目前迫切关注这几个引入:
<script src="js/jquery/jquery.min.js" type="text/javascript"></script>//基本JS
<script type="text/javascript" src="js/backbone/backbone.js"></script>//框架JS

//Saiku 重要的JS
<script type="text/javascript" src="js/saiku/Settings.js"></script>//saiku基本配置->源码
<script type="text/javascript" src="js/saiku/Saiku.js"></script>//初始化saiku基本信息
<script type="text/javascript" src="js/saiku/models/Plugin.js"></script>//访问接口动态获取JS插件
<script type="text/javascript" src="js/saiku/models/Settings.js"></script>//访问接口动态获取CSS插件
<script type="text/javascript" src="js/saiku/adapters/SaikuServer.js"></script>//URL请求交互处理
<script type="text/javascript" src="js/saiku/models/Session.js"></script>//用户状态信息操作类
<script type="text/javascript" src="js/saiku/views/LoginForm.js"></script>//创建用户登录窗口

结论:index.html

 

(2) 首页,你在初始化自己的时候,都干哈了好事?

Saiku.js 跳了出来 ,他说:在全部的js中,哥们儿我有唯一的一个

$(function(){
    //页面初始化加载代码于此
});

我在这里面做了以下的好事,我按顺序说了啊

1、先判断是不是作为BI的PLUGIN存在,如果不是,那我可是一个独立的系统,是需要登录的哟,是就算了撒

2、显然我是被独立了,那我就开始初始化加载吧

3、我第一件事就是要构造一个获取动态JS的接口 URL :/saiku/rest/saiku/info

4、接下来当然是要访问这个接口啦

    |——失败后我不做任何处理,反正我破罐子破摔了
    |——成功后嘿嘿【接口处理代码和返回的JS列表看最后】
    
5、我再去构造一个获取动态CSS的接口 URL:/saiku/rest/saiku/info/ui-settings

6、接下来当然还是要访问这个接口啦

    |——这么说吧,我如果成功success了,我要做以下的事:
        |——加载所有的JS[plugins.size次异步请求]
        |——加载所有的CSS[css.size次异步请求]
    |——如果我不小心失败error
        |——我就只能加载所有的JS[plugins.size次异步请求]啦,你总不能要求我加载获取失败的CSS吧
        
    |——可是不管我是成功还是失败,我要做的事就必须做完,这些事我必做的:
    
        1)创建Session对象
            Saiku.session = new Session({}, {username: Settings.USERNAME,password: Settings.PASSWORD});
            
            在创建的时候会调用check_session方法通过构造/saiku/rest/saiku/session并访问该接口去获取用户session信息
            如果用户session信息为空就创建new LoginForm()登录页
            否则调用load_session方法构建首页空间 - new SessionWorkspace()
                |-其实是访问/saiku/rest/saiku/用户帐号/discover接口获取数据源,成功后返回的connectionsList
                    |-成功后调用process_datasources方法 传入返回的 connectionsList 作为参数
                        |- 根据 connectionsList 执行 prefetch_dimensions 预加载Cube ->  _.delay(this.prefetch_dimensions, 20);
                            
                            钻取层级
                            var connection = this.connections[i];
                            var catalog = connection.catalogs[j];
                            var schema = catalog.schemas[k];
                            var cube = schema.cubes[l];
                            
                            var key = connection.name + "/" + catalog.name + "/" +
                            ((schema.name === "" || schema.name === null) ? "null" : schema.name) +
                            "/" + encodeURIComponent(cube.name);
                            
                            this.cube[key] = new Cube({ key: key });
                            
                            if (Settings.DIMENSION_PREFETCH === true) {
                                this.cube[key].fetch();
                            }
                        |- 最后新建Workspace或者直接打开查询  -> Saiku.tabs.add(new Workspace());
            
        2)创建Toolbar对象
            Saiku.toolbar = new Toolbar();

 

(3) 动态获取JS

1、关键代码 - InfoResource.getAvailablePlugins()

filepath配置在saiku-beans的这个bean里面

<bean id="platformBean" class="org.saiku.service.PlatformUtilsService">
  <property name="path" value="../webapps/saiku/js/saiku/plugins/"/>
</bean>

 

2、动态加载的JS如下

 

(4)  $(function(){}); 源码详细分析

if (! Settings.BIPLUGIN) {//Settings.BIPLUGIN 在settings.js中配置为false

    //执行页面初始化加载
    $(document).ready(function () {
    
        //这个JS对象在js/saiku/models/Plugin.js里面定义
        //完成后构建了访问的url:/saiku/rest/saiku/info
        /* js/saiku/models/Plugin.js
            var PluginCollection = Backbone.Collection.extend({
                model: Plugin,
                url: 'info'
            });
        */
        var plugins = new PluginCollection();
        
        //接着,执行 backbone 的 fetch 方法就去访问了这个rest服务 /saiku/rest/saiku/info
        plugins.fetch({
            //调用成功。返回各个模块的plugin.js的路径
            success: function () {
                
                //这个JS对象在js/saiku/models/Settings.js里面定义
                //完成后构建了访问的url:/saiku/rest/saiku/info/ui-settings
                /* js/saiku/models/Settings.js
                    var SettingsOverrideCollection = Backbone.Collection.extend({
                        model: SettingsOverride,
                        url: 'info/ui-settings'
                    });
                */
                var settingsoverride = new SettingsOverrideCollection();

                //接着执行 backbone 的 fetch 方法就去访问了这个rest服务 /saiku/rest/saiku/info/ui-settings
                settingsoverride.fetch({
                
                    //调用成功。返回一个全局css文件
                    //加载第一个接口返回的JS和第二个接口返回的CSS
                    //并根据创建Session对象的状态去决定到登录页还是首页
                    //创建Toolbar工具栏
                    success: function () {
                        var i = plugins.size();
                        var j = 0;
                        
                        //遍历第一个rest返回的plugin.js,逐个去异步获取
                        plugins.each(function (log) {
                            j = j + 1;
                            if (log.attributes.path != "js/saiku/plugins/I18n/plugin.js") {
                                jQuery.ajax({
                                    async:false,
                                    type:'GET',
                                    url:log.attributes.path,
                                    data:null,
                                    success:function(){
                                        //JS全部遍历完毕后,再遍历第二个接口获取到的CSS
                                        if (j == i) {

                                            var k = settingsoverride.size();
                                            var l = 0;
                                            settingsoverride.each(function (log) {
                                                l = l + 1;

                                                for (var key in log.attributes) {
                                                    Settings[key] = log.attributes[key];
                                                }
                                                if(Settings.CSS != undefined){
                                                    Saiku.loadCSS(Settings.CSS, null)
                                                }
                                                
                                                //CSS全部遍历完毕后,创建一个Session:js/saiku/models/Session.js
                                                //创建session会调用初始化方法,从而调用check_session方法
                                                /**
                                                    check_session: function() {
                                                        if (this.sessionid === null || this.username === null || this.password === null) {
                                                            var that = this;
                                                            this.clear();
                                                            //在这里会调用本页面的url 构造的接口是/saiki/rest/saiku/session
                                                            //调用成功后调用process_session
                                                            /**
                                                                url: function() {return "session";}
                                                            **/
                                                            this.fetch({ success: this.process_session, error: this.brute_force });
                                                        } else {
                                                            this.username = encodeURIComponent(options.username);
                                                            this.load_session();
                                                        }
                                                    },
                                                **/
                                                
                                                /**
                                                    process_session: function(model, response) {
                                                        if ((response === null || response.sessionid == null)) {
                                                            // Open form and retrieve credentials
                                                            Saiku.ui.unblock();
                                                            if (Settings.DEMO) {
                                                                this.form = new DemoLoginForm({ session: this });
                                                            } else {
                                                                
                                                                //第一次访问肯定没有用户信息
                                                                //所以就创建一个LoginForm了
                                                                //至此就完成了首页初次访问登录框的加载
                                                                this.form = new LoginForm({ session: this });
                                                            }
                                                            this.form.render().open();
                                                        } else {
                                                            this.sessionid = response.sessionid;
                                                            this.roles = response.roles;
                                                            this.isAdmin = response.isadmin;
                                                            this.username = encodeURIComponent(response.username);
                                                            this.language = response.language;
                                                            if (typeof this.language != "undefined" && this.language != Saiku.i18n.locale) {
                                                                Saiku.i18n.locale = this.language;
                                                                Saiku.i18n.automatic_i18n();
                                                            }
                                                            this.load_session();
                                                        }

                                                        return this;
                                                    },
                                                **/
                                                
                                                
                                                //再创建工具栏对象:js/saiku/views/Toolbar.js
                                                if (k == l) {
                                                    Saiku.session = new Session({}, {
                                                        username: Settings.USERNAME,
                                                        password: Settings.PASSWORD
                                                    });

                                                    Saiku.toolbar = new Toolbar();
                                                }
                                            });

                                        }
                                    },
                                    dataType:'script'
                                });
                            }
                            else{
                                if (j == i) {

                                    var k = settingsoverride.size();
                                    var l = 0;
                                    settingsoverride.each(function (log) {
                                        l = l + 1;

                                        for (var key in log.attributes) {
                                            Settings[key] = log.attributes[key];
                                        }
                                        if(Settings.CSS != undefined){
                                            Saiku.loadCSS(Settings.CSS, null)
                                        }
                                        if (k == l) {
                                            Saiku.session = new Session({}, {
                                                username: Settings.USERNAME,
                                                password: Settings.PASSWORD
                                            });

                                            Saiku.toolbar = new Toolbar();
                                        }
                                    });

                                }
                            }

                        });


                    },
                    
                    //如果ui-settings访问失败,只加载第一个接口返回的JS
                    //并根据创建Session对象的状态去决定到登录页还是首页
                    //创建Toolbar工具栏
                    error: function () {
                        var i = plugins.size();
                        var j = 0;
                        plugins.each(function (log) {
                            j = j + 1;
                            if (log.attributes.path != "js/saiku/plugins/I18n/plugin.js") {
                                jQuery.ajax({
                                    async:false,
                                    type:'GET',
                                    url:log.attributes.path,
                                    data:null,
                                    success: function(){
                                        if (j == i) {
                                            if(Settings.CSS != undefined){
                                                Saiku.loadCSS(Settings.CSS, null)
                                            }
                                            Saiku.session = new Session({}, {
                                                username: Settings.USERNAME,
                                                password: Settings.PASSWORD
                                            });

                                            Saiku.toolbar = new Toolbar();
                                        }
                                    },
                                    dataType:'script'
                                });
                            }
                            else{
                                if (j == i) {

                                    if(Settings.CSS != undefined){
                                        Saiku.loadCSS(Settings.CSS, null)
                                    }
                                    Saiku.session = new Session({}, {
                                        username: Settings.USERNAME,
                                        password: Settings.PASSWORD
                                    });

                                    Saiku.toolbar = new Toolbar();

                                }
                            }
                        });

                    }
                });
            }
        });
    });
}

 

(5)  Settings.js源码

var Settings = {
    VERSION: "Saiku-${version}",
    BIPLUGIN: false,
    BIPLUGIN5: false,
    BASE_URL: window.location.origin,
    TOMCAT_WEBAPP: "/saiku",
    REST_MOUNT_POINT: "/rest/saiku/",
    DIMENSION_PREFETCH: true,
    DIMENSION_SHOW_ALL: true,
    DIMENSION_SHOW_REDUCED: false,
    ERROR_LOGGING: false,
    I18N_LOCALE: "en",
    // number of erroneous ajax calls in a row before UI cant recover
    ERROR_TOLERANCE: 3,
    QUERY_PROPERTIES: {
        'saiku.olap.query.automatic_execution': true,
        'saiku.olap.query.nonempty': true,
        'saiku.olap.query.nonempty.rows': true,
        'saiku.olap.query.nonempty.columns': true,
        'saiku.ui.render.mode' : 'table',
        'saiku.olap.query.filter' : true,
        'saiku.olap.result.formatter' : "flattened"
    },
    TABLE_LAZY: true,          // Turn lazy loading off / on
    TABLE_LAZY_SIZE: 1000,     // Initial number of items to be rendered
    TABLE_LAZY_LOAD_ITEMS: 20,       // Additional item per scroll
    TABLE_LAZY_LOAD_TIME: 20,  // throttling call of lazy loading items
    /* Valid values for CELLSET_FORMATTER:
     * 1) flattened
     * 2) flat
     */
    CELLSET_FORMATTER: "flattened",
    // limits the number of rows in the result
    // 0 - no limit
    RESULT_LIMIT: 0,
    MEMBERS_FROM_RESULT: true,
    MEMBERS_LIMIT: 3000,
    MEMBERS_SEARCH_LIMIT: 75,
    ALLOW_IMPORT_EXPORT: false,
    ALLOW_PARAMETERS: true,
    PLUGINS: [
        "Chart"
    ],
    DEFAULT_VIEW_STATE: 'view', // could be 'edit' as well
    DEMO: false,
    TELEMETRY_SERVER: 'http://telemetry.analytical-labs.com:7000',
    LOCALSTORAGE_EXPIRATION: 10 * 60 * 60 * 1000 /* 10 hours, in ms */,
    UPGRADE: true,
    EVALUATION_PANEL_LOGIN: true,
    QUERY_OVERWRITE_WARNING: true,
    MAPS: true,
    MAPS_TYPE: 'OSM' // OSM || GMAPS
};

/**
 * Extend settings with query parameters
 */
Settings.GET = function () {
    var qs = document.location.search;
    qs = qs.split("+").join(" ");
    var params = {},
        tokens,
        re = /[?&]?([^=]+)=([^&]*)/g;

    tokens = re.exec(qs);
    while (tokens) {
        var value = decodeURIComponent(tokens[2]);
        if (! isNaN(value)) value = parseInt(value);
        if (value === "true") value = true;
        if (value === "false") value = false;
        if(decodeURIComponent(tokens[1].toUpperCase()).substring(0,5)==="PARAM"){
            params["PARAM"+decodeURIComponent(tokens[1]).substring(5,decodeURIComponent(tokens[1]).length)] = value;
        }
        else{
            params[decodeURIComponent(tokens[1]).toUpperCase()] = value;
        }

        tokens = re.exec(qs);
    }

    return params;
}();
_.extend(Settings, Settings.GET);

Settings.PARAMS = (function() {
    var p = {};
    for (var key in Settings) {
        if (key.match("^PARAM")=="PARAM") {
            p[key] = Settings[key];
        }
    }
    return p;
}());

Settings.REST_URL = Settings.TOMCAT_WEBAPP + Settings.REST_MOUNT_POINT;

// lets assume we dont need a min width/height for table mode
if (Settings.MODE == "table") {
    Settings.DIMENSION_PREFETCH = false;
    $('body, html').css('min-height',0);
    $('body, html').css('min-width',0);

}
if (Settings.BIPLUGIN5) {
    Settings.BIPLUGIN = true;
}

Settings.INITIAL_QUERY = false;
if (document.location.hash) {
    var hash = document.location.hash;
    if (hash.length > 11 && hash.substring(1, 11) == "query/open") {
        Settings.INITIAL_QUERY = true;
    }
}

Settings.MONDRIAN_LOCALES = {
    "English": "en_US",
    "Dutch": "nl_BE",
    "French": "fr_FR"
};

/**
 * < IE9 doesn't support Array.indexOf
 */
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt /*, from*/)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0)
      from += len;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}

var tagsToReplace = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;'
};

function replaceTag(tag) {
    return tagsToReplace[tag] || tag;
}

function safe_tags_replace(str) {
    return str.replace(/[&<>]/g, replaceTag);
}

if ($.blockUI) {
    $.blockUI.defaults.css = {};
    $.blockUI.defaults.overlayCSS = {};
    $.blockUI.defaults.blockMsgClass = 'processing';
    $.blockUI.defaults.fadeOut = 0;
    $.blockUI.defaults.fadeIn = 0;
    $.blockUI.defaults.ignoreIfBlocked = false;

}

if (window.location.hostname && (window.location.hostname == "try.meteorite.bi" )) {
    Settings.USERNAME = "admin";
    Settings.PASSWORD = "admin";
    Settings.DEMO = true;
    Settings.UPGRADE = false;
}

var isIE = (function(){
    var undef, v = 3;

    var dav = navigator.appVersion;

    if(dav.indexOf('MSIE') != -1) {
        v  = parseFloat(dav.split('MSIE ')[1]);
        return v> 4 ? v : false;
    }
    return false;

}());

var isFF = (function(userAgent) {
    'use strict';

    return !!userAgent.match(/Firefox/);
}(navigator.userAgent));

var isMobile = (function(userAgent) {
  'use strict';

  return !!userAgent.match(/android|webos|ip(hone|ad|od)|opera (mini|mobi|tablet)|iemobile|windows.+(phone|touch)|mobile|fennec|kindle (Fire)|Silk|maemo|blackberry|playbook|bb10\; (touch|kbd)|Symbian(OS)|Ubuntu Touch/i);
}(navigator.userAgent));

 

posted @ 2015-10-21 12:10  Aviva_ye  阅读(2399)  评论(0编辑  收藏  举报